| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 22 matching lines...) Expand all Loading... |
| 33 #include "api.h" | 33 #include "api.h" |
| 34 #include "arguments.h" | 34 #include "arguments.h" |
| 35 #include "codegen.h" | 35 #include "codegen.h" |
| 36 #include "compilation-cache.h" | 36 #include "compilation-cache.h" |
| 37 #include "compiler.h" | 37 #include "compiler.h" |
| 38 #include "cpu.h" | 38 #include "cpu.h" |
| 39 #include "dateparser-inl.h" | 39 #include "dateparser-inl.h" |
| 40 #include "debug.h" | 40 #include "debug.h" |
| 41 #include "deoptimizer.h" | 41 #include "deoptimizer.h" |
| 42 #include "execution.h" | 42 #include "execution.h" |
| 43 #include "global-handles.h" |
| 43 #include "jsregexp.h" | 44 #include "jsregexp.h" |
| 44 #include "liveedit.h" | 45 #include "liveedit.h" |
| 46 #include "liveobjectlist-inl.h" |
| 45 #include "parser.h" | 47 #include "parser.h" |
| 46 #include "platform.h" | 48 #include "platform.h" |
| 47 #include "runtime.h" | 49 #include "runtime.h" |
| 48 #include "runtime-profiler.h" | 50 #include "runtime-profiler.h" |
| 49 #include "scopeinfo.h" | 51 #include "scopeinfo.h" |
| 50 #include "smart-pointer.h" | 52 #include "smart-pointer.h" |
| 51 #include "stub-cache.h" | 53 #include "stub-cache.h" |
| 52 #include "v8threads.h" | 54 #include "v8threads.h" |
| 53 #include "string-search.h" | 55 #include "string-search.h" |
| 54 | 56 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 // an array. | 154 // an array. |
| 153 if (attributes != NONE) continue; | 155 if (attributes != NONE) continue; |
| 154 Object* value = | 156 Object* value = |
| 155 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); | 157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); |
| 156 if (value->IsJSObject()) { | 158 if (value->IsJSObject()) { |
| 157 JSObject* js_object = JSObject::cast(value); | 159 JSObject* js_object = JSObject::cast(value); |
| 158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); | 160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); |
| 159 if (!maybe_result->ToObject(&result)) return maybe_result; | 161 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 160 } | 162 } |
| 161 { MaybeObject* maybe_result = | 163 { MaybeObject* maybe_result = |
| 162 copy->SetProperty(key_string, result, NONE); | 164 // Creating object copy for literals. No strict mode needed. |
| 165 copy->SetProperty(key_string, result, NONE, kNonStrictMode); |
| 163 if (!maybe_result->ToObject(&result)) return maybe_result; | 166 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 164 } | 167 } |
| 165 } | 168 } |
| 166 } | 169 } |
| 167 } | 170 } |
| 168 | 171 |
| 169 // Deep copy local elements. | 172 // Deep copy local elements. |
| 170 // Pixel elements cannot be created using an object literal. | 173 // Pixel elements cannot be created using an object literal. |
| 171 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements()); | 174 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements()); |
| 172 switch (copy->GetElementsKind()) { | 175 switch (copy->GetElementsKind()) { |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 JSFunction* constructor = | 569 JSFunction* constructor = |
| 567 isolate->context()->global_context()-> | 570 isolate->context()->global_context()-> |
| 568 context_extension_function(); | 571 context_extension_function(); |
| 569 Object* object; | 572 Object* object; |
| 570 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor); | 573 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor); |
| 571 if (!maybe_object->ToObject(&object)) return maybe_object; | 574 if (!maybe_object->ToObject(&object)) return maybe_object; |
| 572 } | 575 } |
| 573 // Assign the exception value to the catch variable and make sure | 576 // Assign the exception value to the catch variable and make sure |
| 574 // that the catch variable is DontDelete. | 577 // that the catch variable is DontDelete. |
| 575 { MaybeObject* maybe_value = | 578 { MaybeObject* maybe_value = |
| 576 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE); | 579 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4. |
| 580 JSObject::cast(object)->SetProperty( |
| 581 key, value, DONT_DELETE, kNonStrictMode); |
| 577 if (!maybe_value->ToObject(&value)) return maybe_value; | 582 if (!maybe_value->ToObject(&value)) return maybe_value; |
| 578 } | 583 } |
| 579 return object; | 584 return object; |
| 580 } | 585 } |
| 581 | 586 |
| 582 | 587 |
| 583 static MaybeObject* Runtime_ClassOf(RUNTIME_CALLING_CONVENTION) { | 588 static MaybeObject* Runtime_ClassOf(RUNTIME_CALLING_CONVENTION) { |
| 584 RUNTIME_GET_ISOLATE; | 589 RUNTIME_GET_ISOLATE; |
| 585 NoHandleAllocation ha; | 590 NoHandleAllocation ha; |
| 586 ASSERT(args.length() == 1); | 591 ASSERT(args.length() == 1); |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 elms->set(VALUE_INDEX, *substr); | 815 elms->set(VALUE_INDEX, *substr); |
| 811 elms->set(WRITABLE_INDEX, heap->false_value()); | 816 elms->set(WRITABLE_INDEX, heap->false_value()); |
| 812 elms->set(ENUMERABLE_INDEX, heap->false_value()); | 817 elms->set(ENUMERABLE_INDEX, heap->false_value()); |
| 813 elms->set(CONFIGURABLE_INDEX, heap->false_value()); | 818 elms->set(CONFIGURABLE_INDEX, heap->false_value()); |
| 814 return *desc; | 819 return *desc; |
| 815 } | 820 } |
| 816 | 821 |
| 817 case JSObject::INTERCEPTED_ELEMENT: | 822 case JSObject::INTERCEPTED_ELEMENT: |
| 818 case JSObject::FAST_ELEMENT: { | 823 case JSObject::FAST_ELEMENT: { |
| 819 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 824 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); |
| 820 elms->set(VALUE_INDEX, *GetElement(obj, index)); | 825 Handle<Object> value = GetElement(obj, index); |
| 826 elms->set(VALUE_INDEX, *value); |
| 821 elms->set(WRITABLE_INDEX, heap->true_value()); | 827 elms->set(WRITABLE_INDEX, heap->true_value()); |
| 822 elms->set(ENUMERABLE_INDEX, heap->true_value()); | 828 elms->set(ENUMERABLE_INDEX, heap->true_value()); |
| 823 elms->set(CONFIGURABLE_INDEX, heap->true_value()); | 829 elms->set(CONFIGURABLE_INDEX, heap->true_value()); |
| 824 return *desc; | 830 return *desc; |
| 825 } | 831 } |
| 826 | 832 |
| 827 case JSObject::DICTIONARY_ELEMENT: { | 833 case JSObject::DICTIONARY_ELEMENT: { |
| 828 Handle<JSObject> holder = obj; | 834 Handle<JSObject> holder = obj; |
| 829 if (obj->IsJSGlobalProxy()) { | 835 if (obj->IsJSGlobalProxy()) { |
| 830 Object* proto = obj->GetPrototype(); | 836 Object* proto = obj->GetPrototype(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 843 FixedArray::cast(dictionary->ValueAt(entry)); | 849 FixedArray::cast(dictionary->ValueAt(entry)); |
| 844 elms->set(IS_ACCESSOR_INDEX, heap->true_value()); | 850 elms->set(IS_ACCESSOR_INDEX, heap->true_value()); |
| 845 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) { | 851 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) { |
| 846 elms->set(GETTER_INDEX, callbacks->get(0)); | 852 elms->set(GETTER_INDEX, callbacks->get(0)); |
| 847 } | 853 } |
| 848 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { | 854 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { |
| 849 elms->set(SETTER_INDEX, callbacks->get(1)); | 855 elms->set(SETTER_INDEX, callbacks->get(1)); |
| 850 } | 856 } |
| 851 break; | 857 break; |
| 852 } | 858 } |
| 853 case NORMAL: | 859 case NORMAL: { |
| 854 // This is a data property. | 860 // This is a data property. |
| 855 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 861 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); |
| 856 elms->set(VALUE_INDEX, *GetElement(obj, index)); | 862 Handle<Object> value = GetElement(obj, index); |
| 863 elms->set(VALUE_INDEX, *value); |
| 857 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly())); | 864 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly())); |
| 858 break; | 865 break; |
| 866 } |
| 859 default: | 867 default: |
| 860 UNREACHABLE(); | 868 UNREACHABLE(); |
| 861 break; | 869 break; |
| 862 } | 870 } |
| 863 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum())); | 871 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum())); |
| 864 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete())); | 872 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete())); |
| 865 return *desc; | 873 return *desc; |
| 866 } | 874 } |
| 867 } | 875 } |
| 868 } | 876 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1034 isolate->factory()->NewStringFromAscii(CStrVector(type)); | 1042 isolate->factory()->NewStringFromAscii(CStrVector(type)); |
| 1035 Handle<Object> args[2] = { type_handle, name }; | 1043 Handle<Object> args[2] = { type_handle, name }; |
| 1036 Handle<Object> error = | 1044 Handle<Object> error = |
| 1037 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); | 1045 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); |
| 1038 return isolate->Throw(*error); | 1046 return isolate->Throw(*error); |
| 1039 } | 1047 } |
| 1040 | 1048 |
| 1041 | 1049 |
| 1042 static MaybeObject* Runtime_DeclareGlobals(RUNTIME_CALLING_CONVENTION) { | 1050 static MaybeObject* Runtime_DeclareGlobals(RUNTIME_CALLING_CONVENTION) { |
| 1043 RUNTIME_GET_ISOLATE; | 1051 RUNTIME_GET_ISOLATE; |
| 1052 ASSERT(args.length() == 4); |
| 1044 HandleScope scope(isolate); | 1053 HandleScope scope(isolate); |
| 1045 Handle<GlobalObject> global = Handle<GlobalObject>( | 1054 Handle<GlobalObject> global = Handle<GlobalObject>( |
| 1046 isolate->context()->global()); | 1055 isolate->context()->global()); |
| 1047 | 1056 |
| 1048 Handle<Context> context = args.at<Context>(0); | 1057 Handle<Context> context = args.at<Context>(0); |
| 1049 CONVERT_ARG_CHECKED(FixedArray, pairs, 1); | 1058 CONVERT_ARG_CHECKED(FixedArray, pairs, 1); |
| 1050 bool is_eval = Smi::cast(args[2])->value() == 1; | 1059 bool is_eval = Smi::cast(args[2])->value() == 1; |
| 1060 StrictModeFlag strict_mode = |
| 1061 static_cast<StrictModeFlag>(Smi::cast(args[3])->value()); |
| 1062 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); |
| 1051 | 1063 |
| 1052 // Compute the property attributes. According to ECMA-262, section | 1064 // Compute the property attributes. According to ECMA-262, section |
| 1053 // 13, page 71, the property must be read-only and | 1065 // 13, page 71, the property must be read-only and |
| 1054 // non-deletable. However, neither SpiderMonkey nor KJS creates the | 1066 // non-deletable. However, neither SpiderMonkey nor KJS creates the |
| 1055 // property as read-only, so we don't either. | 1067 // property as read-only, so we don't either. |
| 1056 PropertyAttributes base = is_eval ? NONE : DONT_DELETE; | 1068 PropertyAttributes base = is_eval ? NONE : DONT_DELETE; |
| 1057 | 1069 |
| 1058 // Traverse the name/value pairs and set the properties. | 1070 // Traverse the name/value pairs and set the properties. |
| 1059 int length = pairs->length(); | 1071 int length = pairs->length(); |
| 1060 for (int i = 0; i < length; i += 2) { | 1072 for (int i = 0; i < length; i += 2) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1092 const char* type = (is_read_only) ? "const" : "var"; | 1104 const char* type = (is_read_only) ? "const" : "var"; |
| 1093 return ThrowRedeclarationError(isolate, type, name); | 1105 return ThrowRedeclarationError(isolate, type, name); |
| 1094 }; | 1106 }; |
| 1095 // The property already exists without conflicting: Go to | 1107 // The property already exists without conflicting: Go to |
| 1096 // the next declaration. | 1108 // the next declaration. |
| 1097 continue; | 1109 continue; |
| 1098 } | 1110 } |
| 1099 // Fall-through and introduce the absent property by using | 1111 // Fall-through and introduce the absent property by using |
| 1100 // SetProperty. | 1112 // SetProperty. |
| 1101 } else { | 1113 } else { |
| 1114 // For const properties, we treat a callback with this name |
| 1115 // even in the prototype as a conflicting declaration. |
| 1116 if (is_const_property && (lookup.type() == CALLBACKS)) { |
| 1117 return ThrowRedeclarationError(isolate, "const", name); |
| 1118 } |
| 1119 // Otherwise, we check for locally conflicting declarations. |
| 1102 if (is_local && (is_read_only || is_const_property)) { | 1120 if (is_local && (is_read_only || is_const_property)) { |
| 1103 const char* type = (is_read_only) ? "const" : "var"; | 1121 const char* type = (is_read_only) ? "const" : "var"; |
| 1104 return ThrowRedeclarationError(isolate, type, name); | 1122 return ThrowRedeclarationError(isolate, type, name); |
| 1105 } | 1123 } |
| 1106 // The property already exists without conflicting: Go to | 1124 // The property already exists without conflicting: Go to |
| 1107 // the next declaration. | 1125 // the next declaration. |
| 1108 continue; | 1126 continue; |
| 1109 } | 1127 } |
| 1110 } | 1128 } |
| 1111 } else { | 1129 } else { |
| 1112 // Copy the function and update its context. Use it as value. | 1130 // Copy the function and update its context. Use it as value. |
| 1113 Handle<SharedFunctionInfo> shared = | 1131 Handle<SharedFunctionInfo> shared = |
| 1114 Handle<SharedFunctionInfo>::cast(value); | 1132 Handle<SharedFunctionInfo>::cast(value); |
| 1115 Handle<JSFunction> function = | 1133 Handle<JSFunction> function = |
| 1116 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, | 1134 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, |
| 1117 context, | 1135 context, |
| 1118 TENURED); | 1136 TENURED); |
| 1119 value = function; | 1137 value = function; |
| 1120 } | 1138 } |
| 1121 | 1139 |
| 1122 LookupResult lookup; | 1140 LookupResult lookup; |
| 1123 global->LocalLookup(*name, &lookup); | 1141 global->LocalLookup(*name, &lookup); |
| 1124 | 1142 |
| 1125 PropertyAttributes attributes = is_const_property | 1143 PropertyAttributes attributes = is_const_property |
| 1126 ? static_cast<PropertyAttributes>(base | READ_ONLY) | 1144 ? static_cast<PropertyAttributes>(base | READ_ONLY) |
| 1127 : base; | 1145 : base; |
| 1128 | 1146 |
| 1129 if (lookup.IsProperty()) { | 1147 // There's a local property that we need to overwrite because |
| 1130 // There's a local property that we need to overwrite because | 1148 // we're either declaring a function or there's an interceptor |
| 1131 // we're either declaring a function or there's an interceptor | 1149 // that claims the property is absent. |
| 1132 // that claims the property is absent. | 1150 // |
| 1151 // Check for conflicting re-declarations. We cannot have |
| 1152 // conflicting types in case of intercepted properties because |
| 1153 // they are absent. |
| 1154 if (lookup.IsProperty() && |
| 1155 (lookup.type() != INTERCEPTOR) && |
| 1156 (lookup.IsReadOnly() || is_const_property)) { |
| 1157 const char* type = (lookup.IsReadOnly()) ? "const" : "var"; |
| 1158 return ThrowRedeclarationError(isolate, type, name); |
| 1159 } |
| 1133 | 1160 |
| 1134 // Check for conflicting re-declarations. We cannot have | 1161 // Safari does not allow the invocation of callback setters for |
| 1135 // conflicting types in case of intercepted properties because | 1162 // function declarations. To mimic this behavior, we do not allow |
| 1136 // they are absent. | 1163 // the invocation of setters for function values. This makes a |
| 1137 if (lookup.type() != INTERCEPTOR && | 1164 // difference for global functions with the same names as event |
| 1138 (lookup.IsReadOnly() || is_const_property)) { | 1165 // handlers such as "function onload() {}". Firefox does call the |
| 1139 const char* type = (lookup.IsReadOnly()) ? "const" : "var"; | 1166 // onload setter in those case and Safari does not. We follow |
| 1140 return ThrowRedeclarationError(isolate, type, name); | 1167 // Safari for compatibility. |
| 1168 if (value->IsJSFunction()) { |
| 1169 // Do not change DONT_DELETE to false from true. |
| 1170 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { |
| 1171 attributes = static_cast<PropertyAttributes>( |
| 1172 attributes | (lookup.GetAttributes() & DONT_DELETE)); |
| 1141 } | 1173 } |
| 1142 Handle<Object> result = SetProperty(global, name, value, attributes); | 1174 RETURN_IF_EMPTY_HANDLE(isolate, |
| 1143 if (result.is_null()) { | 1175 SetLocalPropertyIgnoreAttributes(global, |
| 1144 ASSERT(isolate->has_pending_exception()); | 1176 name, |
| 1145 return Failure::Exception(); | 1177 value, |
| 1146 } | 1178 attributes)); |
| 1147 } else { | 1179 } else { |
| 1148 // If a property with this name does not already exist on the | 1180 RETURN_IF_EMPTY_HANDLE(isolate, |
| 1149 // global object add the property locally. We take special | 1181 SetProperty(global, |
| 1150 // precautions to always add it as a local property even in case | 1182 name, |
| 1151 // of callbacks in the prototype chain (this rules out using | 1183 value, |
| 1152 // SetProperty). Also, we must use the handle-based version to | 1184 attributes, |
| 1153 // avoid GC issues. | 1185 strict_mode)); |
| 1154 Handle<Object> result = | |
| 1155 SetLocalPropertyIgnoreAttributes(global, name, value, attributes); | |
| 1156 if (result.is_null()) { | |
| 1157 ASSERT(isolate->has_pending_exception()); | |
| 1158 return Failure::Exception(); | |
| 1159 } | |
| 1160 } | 1186 } |
| 1161 } | 1187 } |
| 1162 | 1188 |
| 1163 ASSERT(!isolate->has_pending_exception()); | 1189 ASSERT(!isolate->has_pending_exception()); |
| 1164 return isolate->heap()->undefined_value(); | 1190 return isolate->heap()->undefined_value(); |
| 1165 } | 1191 } |
| 1166 | 1192 |
| 1167 | 1193 |
| 1168 static MaybeObject* Runtime_DeclareContextSlot(RUNTIME_CALLING_CONVENTION) { | 1194 static MaybeObject* Runtime_DeclareContextSlot(RUNTIME_CALLING_CONVENTION) { |
| 1169 RUNTIME_GET_ISOLATE; | 1195 RUNTIME_GET_ISOLATE; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 } | 1236 } |
| 1211 } else { | 1237 } else { |
| 1212 // The holder is an arguments object. | 1238 // The holder is an arguments object. |
| 1213 Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); | 1239 Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); |
| 1214 Handle<Object> result = SetElement(arguments, index, initial_value); | 1240 Handle<Object> result = SetElement(arguments, index, initial_value); |
| 1215 if (result.is_null()) return Failure::Exception(); | 1241 if (result.is_null()) return Failure::Exception(); |
| 1216 } | 1242 } |
| 1217 } else { | 1243 } else { |
| 1218 // Slow case: The property is not in the FixedArray part of the context. | 1244 // Slow case: The property is not in the FixedArray part of the context. |
| 1219 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); | 1245 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); |
| 1220 Handle<Object> result = | 1246 RETURN_IF_EMPTY_HANDLE( |
| 1221 SetProperty(context_ext, name, initial_value, mode); | 1247 isolate, |
| 1222 if (result.is_null()) return Failure::Exception(); | 1248 SetProperty(context_ext, name, initial_value, |
| 1249 mode, kNonStrictMode)); |
| 1223 } | 1250 } |
| 1224 } | 1251 } |
| 1225 | 1252 |
| 1226 } else { | 1253 } else { |
| 1227 // The property is not in the function context. It needs to be | 1254 // The property is not in the function context. It needs to be |
| 1228 // "declared" in the function context's extension context, or in the | 1255 // "declared" in the function context's extension context, or in the |
| 1229 // global context. | 1256 // global context. |
| 1230 Handle<JSObject> context_ext; | 1257 Handle<JSObject> context_ext; |
| 1231 if (context->has_extension()) { | 1258 if (context->has_extension()) { |
| 1232 // The function context's extension context exists - use it. | 1259 // The function context's extension context exists - use it. |
| 1233 context_ext = Handle<JSObject>(context->extension()); | 1260 context_ext = Handle<JSObject>(context->extension()); |
| 1234 } else { | 1261 } else { |
| 1235 // The function context's extension context does not exists - allocate | 1262 // The function context's extension context does not exists - allocate |
| 1236 // it. | 1263 // it. |
| 1237 context_ext = isolate->factory()->NewJSObject( | 1264 context_ext = isolate->factory()->NewJSObject( |
| 1238 isolate->context_extension_function()); | 1265 isolate->context_extension_function()); |
| 1239 // And store it in the extension slot. | 1266 // And store it in the extension slot. |
| 1240 context->set_extension(*context_ext); | 1267 context->set_extension(*context_ext); |
| 1241 } | 1268 } |
| 1242 ASSERT(*context_ext != NULL); | 1269 ASSERT(*context_ext != NULL); |
| 1243 | 1270 |
| 1244 // Declare the property by setting it to the initial value if provided, | 1271 // Declare the property by setting it to the initial value if provided, |
| 1245 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for | 1272 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for |
| 1246 // constant declarations). | 1273 // constant declarations). |
| 1247 ASSERT(!context_ext->HasLocalProperty(*name)); | 1274 ASSERT(!context_ext->HasLocalProperty(*name)); |
| 1248 Handle<Object> value(isolate->heap()->undefined_value(), isolate); | 1275 Handle<Object> value(isolate->heap()->undefined_value(), isolate); |
| 1249 if (*initial_value != NULL) value = initial_value; | 1276 if (*initial_value != NULL) value = initial_value; |
| 1250 Handle<Object> result = SetProperty(context_ext, name, value, mode); | 1277 // Declaring a const context slot is a conflicting declaration if |
| 1251 if (result.is_null()) return Failure::Exception(); | 1278 // there is a callback with that name in a prototype. It is |
| 1279 // allowed to introduce const variables in |
| 1280 // JSContextExtensionObjects. They are treated specially in |
| 1281 // SetProperty and no setters are invoked for those since they are |
| 1282 // not real JSObjects. |
| 1283 if (initial_value->IsTheHole() && |
| 1284 !context_ext->IsJSContextExtensionObject()) { |
| 1285 LookupResult lookup; |
| 1286 context_ext->Lookup(*name, &lookup); |
| 1287 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) { |
| 1288 return ThrowRedeclarationError(isolate, "const", name); |
| 1289 } |
| 1290 } |
| 1291 RETURN_IF_EMPTY_HANDLE(isolate, |
| 1292 SetProperty(context_ext, name, value, mode, |
| 1293 kNonStrictMode)); |
| 1252 } | 1294 } |
| 1253 | 1295 |
| 1254 return isolate->heap()->undefined_value(); | 1296 return isolate->heap()->undefined_value(); |
| 1255 } | 1297 } |
| 1256 | 1298 |
| 1257 | 1299 |
| 1258 static MaybeObject* Runtime_InitializeVarGlobal(RUNTIME_CALLING_CONVENTION) { | 1300 static MaybeObject* Runtime_InitializeVarGlobal(RUNTIME_CALLING_CONVENTION) { |
| 1259 RUNTIME_GET_ISOLATE; | 1301 RUNTIME_GET_ISOLATE; |
| 1260 NoHandleAllocation nha; | 1302 NoHandleAllocation nha; |
| 1303 // args[0] == name |
| 1304 // args[1] == strict_mode |
| 1305 // args[2] == value (optional) |
| 1261 | 1306 |
| 1262 // Determine if we need to assign to the variable if it already | 1307 // Determine if we need to assign to the variable if it already |
| 1263 // exists (based on the number of arguments). | 1308 // exists (based on the number of arguments). |
| 1264 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); | 1309 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); |
| 1265 bool assign = args.length() == 2; | 1310 bool assign = args.length() == 3; |
| 1266 | 1311 |
| 1267 CONVERT_ARG_CHECKED(String, name, 0); | 1312 CONVERT_ARG_CHECKED(String, name, 0); |
| 1268 GlobalObject* global = isolate->context()->global(); | 1313 GlobalObject* global = isolate->context()->global(); |
| 1314 RUNTIME_ASSERT(args[1]->IsSmi()); |
| 1315 StrictModeFlag strict_mode = |
| 1316 static_cast<StrictModeFlag>(Smi::cast(args[1])->value()); |
| 1317 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); |
| 1269 | 1318 |
| 1270 // According to ECMA-262, section 12.2, page 62, the property must | 1319 // According to ECMA-262, section 12.2, page 62, the property must |
| 1271 // not be deletable. | 1320 // not be deletable. |
| 1272 PropertyAttributes attributes = DONT_DELETE; | 1321 PropertyAttributes attributes = DONT_DELETE; |
| 1273 | 1322 |
| 1274 // Lookup the property locally in the global object. If it isn't | 1323 // Lookup the property locally in the global object. If it isn't |
| 1275 // there, there is a property with this name in the prototype chain. | 1324 // there, there is a property with this name in the prototype chain. |
| 1276 // We follow Safari and Firefox behavior and only set the property | 1325 // We follow Safari and Firefox behavior and only set the property |
| 1277 // locally if there is an explicit initialization value that we have | 1326 // locally if there is an explicit initialization value that we have |
| 1278 // to assign to the property. When adding the property we take | 1327 // to assign to the property. |
| 1279 // special precautions to always add it as a local property even in | |
| 1280 // case of callbacks in the prototype chain (this rules out using | |
| 1281 // SetProperty). We have SetLocalPropertyIgnoreAttributes for | |
| 1282 // this. | |
| 1283 // Note that objects can have hidden prototypes, so we need to traverse | 1328 // Note that objects can have hidden prototypes, so we need to traverse |
| 1284 // the whole chain of hidden prototypes to do a 'local' lookup. | 1329 // the whole chain of hidden prototypes to do a 'local' lookup. |
| 1285 JSObject* real_holder = global; | 1330 JSObject* real_holder = global; |
| 1286 LookupResult lookup; | 1331 LookupResult lookup; |
| 1287 while (true) { | 1332 while (true) { |
| 1288 real_holder->LocalLookup(*name, &lookup); | 1333 real_holder->LocalLookup(*name, &lookup); |
| 1289 if (lookup.IsProperty()) { | 1334 if (lookup.IsProperty()) { |
| 1290 // Determine if this is a redeclaration of something read-only. | 1335 // Determine if this is a redeclaration of something read-only. |
| 1291 if (lookup.IsReadOnly()) { | 1336 if (lookup.IsReadOnly()) { |
| 1292 // If we found readonly property on one of hidden prototypes, | 1337 // If we found readonly property on one of hidden prototypes, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1318 } | 1363 } |
| 1319 } | 1364 } |
| 1320 | 1365 |
| 1321 if (found && !assign) { | 1366 if (found && !assign) { |
| 1322 // The global property is there and we're not assigning any value | 1367 // The global property is there and we're not assigning any value |
| 1323 // to it. Just return. | 1368 // to it. Just return. |
| 1324 return isolate->heap()->undefined_value(); | 1369 return isolate->heap()->undefined_value(); |
| 1325 } | 1370 } |
| 1326 | 1371 |
| 1327 // Assign the value (or undefined) to the property. | 1372 // Assign the value (or undefined) to the property. |
| 1328 Object* value = (assign) ? args[1] : isolate->heap()->undefined_value(); | 1373 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value(); |
| 1329 return real_holder->SetProperty(&lookup, *name, value, attributes); | 1374 return real_holder->SetProperty( |
| 1375 &lookup, *name, value, attributes, strict_mode); |
| 1330 } | 1376 } |
| 1331 | 1377 |
| 1332 Object* proto = real_holder->GetPrototype(); | 1378 Object* proto = real_holder->GetPrototype(); |
| 1333 if (!proto->IsJSObject()) | 1379 if (!proto->IsJSObject()) |
| 1334 break; | 1380 break; |
| 1335 | 1381 |
| 1336 if (!JSObject::cast(proto)->map()->is_hidden_prototype()) | 1382 if (!JSObject::cast(proto)->map()->is_hidden_prototype()) |
| 1337 break; | 1383 break; |
| 1338 | 1384 |
| 1339 real_holder = JSObject::cast(proto); | 1385 real_holder = JSObject::cast(proto); |
| 1340 } | 1386 } |
| 1341 | 1387 |
| 1342 global = isolate->context()->global(); | 1388 global = isolate->context()->global(); |
| 1343 if (assign) { | 1389 if (assign) { |
| 1344 return global->SetLocalPropertyIgnoreAttributes(*name, | 1390 return global->SetProperty(*name, args[2], attributes, strict_mode); |
| 1345 args[1], | |
| 1346 attributes); | |
| 1347 } | 1391 } |
| 1348 return isolate->heap()->undefined_value(); | 1392 return isolate->heap()->undefined_value(); |
| 1349 } | 1393 } |
| 1350 | 1394 |
| 1351 | 1395 |
| 1352 static MaybeObject* Runtime_InitializeConstGlobal(RUNTIME_CALLING_CONVENTION) { | 1396 static MaybeObject* Runtime_InitializeConstGlobal(RUNTIME_CALLING_CONVENTION) { |
| 1353 RUNTIME_GET_ISOLATE; | 1397 RUNTIME_GET_ISOLATE; |
| 1354 // All constants are declared with an initial value. The name | 1398 // All constants are declared with an initial value. The name |
| 1355 // of the constant is the first argument and the initial value | 1399 // of the constant is the first argument and the initial value |
| 1356 // is the second. | 1400 // is the second. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1394 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { | 1438 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { |
| 1395 return ThrowRedeclarationError(isolate, "var", name); | 1439 return ThrowRedeclarationError(isolate, "var", name); |
| 1396 } | 1440 } |
| 1397 | 1441 |
| 1398 // Restore global object from context (in case of GC) and continue | 1442 // Restore global object from context (in case of GC) and continue |
| 1399 // with setting the value because the property is either absent or | 1443 // with setting the value because the property is either absent or |
| 1400 // read-only. We also have to do redo the lookup. | 1444 // read-only. We also have to do redo the lookup. |
| 1401 HandleScope handle_scope(isolate); | 1445 HandleScope handle_scope(isolate); |
| 1402 Handle<GlobalObject> global(isolate->context()->global()); | 1446 Handle<GlobalObject> global(isolate->context()->global()); |
| 1403 | 1447 |
| 1404 // BUG 1213579: Handle the case where we have to set a read-only | 1448 // BUG 1213575: Handle the case where we have to set a read-only |
| 1405 // property through an interceptor and only do it if it's | 1449 // property through an interceptor and only do it if it's |
| 1406 // uninitialized, e.g. the hole. Nirk... | 1450 // uninitialized, e.g. the hole. Nirk... |
| 1407 SetProperty(global, name, value, attributes); | 1451 // Passing non-strict mode because the property is writable. |
| 1452 RETURN_IF_EMPTY_HANDLE(isolate, |
| 1453 SetProperty(global, |
| 1454 name, |
| 1455 value, |
| 1456 attributes, |
| 1457 kNonStrictMode)); |
| 1408 return *value; | 1458 return *value; |
| 1409 } | 1459 } |
| 1410 | 1460 |
| 1411 // Set the value, but only we're assigning the initial value to a | 1461 // Set the value, but only we're assigning the initial value to a |
| 1412 // constant. For now, we determine this by checking if the | 1462 // constant. For now, we determine this by checking if the |
| 1413 // current value is the hole. | 1463 // current value is the hole. |
| 1464 // Strict mode handling not needed (const disallowed in strict mode). |
| 1414 PropertyType type = lookup.type(); | 1465 PropertyType type = lookup.type(); |
| 1415 if (type == FIELD) { | 1466 if (type == FIELD) { |
| 1416 FixedArray* properties = global->properties(); | 1467 FixedArray* properties = global->properties(); |
| 1417 int index = lookup.GetFieldIndex(); | 1468 int index = lookup.GetFieldIndex(); |
| 1418 if (properties->get(index)->IsTheHole()) { | 1469 if (properties->get(index)->IsTheHole()) { |
| 1419 properties->set(index, *value); | 1470 properties->set(index, *value); |
| 1420 } | 1471 } |
| 1421 } else if (type == NORMAL) { | 1472 } else if (type == NORMAL) { |
| 1422 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) { | 1473 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) { |
| 1423 global->SetNormalizedProperty(&lookup, *value); | 1474 global->SetNormalizedProperty(&lookup, *value); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1482 SetElement(arguments, index, value); | 1533 SetElement(arguments, index, value); |
| 1483 } | 1534 } |
| 1484 return *value; | 1535 return *value; |
| 1485 } | 1536 } |
| 1486 | 1537 |
| 1487 // The property could not be found, we introduce it in the global | 1538 // The property could not be found, we introduce it in the global |
| 1488 // context. | 1539 // context. |
| 1489 if (attributes == ABSENT) { | 1540 if (attributes == ABSENT) { |
| 1490 Handle<JSObject> global = Handle<JSObject>( | 1541 Handle<JSObject> global = Handle<JSObject>( |
| 1491 isolate->context()->global()); | 1542 isolate->context()->global()); |
| 1492 SetProperty(global, name, value, NONE); | 1543 // Strict mode not needed (const disallowed in strict mode). |
| 1544 RETURN_IF_EMPTY_HANDLE( |
| 1545 isolate, |
| 1546 SetProperty(global, name, value, NONE, kNonStrictMode)); |
| 1493 return *value; | 1547 return *value; |
| 1494 } | 1548 } |
| 1495 | 1549 |
| 1496 // The property was present in a context extension object. | 1550 // The property was present in a context extension object. |
| 1497 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); | 1551 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); |
| 1498 | 1552 |
| 1499 if (*context_ext == context->extension()) { | 1553 if (*context_ext == context->extension()) { |
| 1500 // This is the property that was introduced by the const | 1554 // This is the property that was introduced by the const |
| 1501 // declaration. Set it if it hasn't been set before. NOTE: We | 1555 // declaration. Set it if it hasn't been set before. NOTE: We |
| 1502 // cannot use GetProperty() to get the current value as it | 1556 // cannot use GetProperty() to get the current value as it |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1519 } | 1573 } |
| 1520 } else { | 1574 } else { |
| 1521 // We should not reach here. Any real, named property should be | 1575 // We should not reach here. Any real, named property should be |
| 1522 // either a field or a dictionary slot. | 1576 // either a field or a dictionary slot. |
| 1523 UNREACHABLE(); | 1577 UNREACHABLE(); |
| 1524 } | 1578 } |
| 1525 } else { | 1579 } else { |
| 1526 // The property was found in a different context extension object. | 1580 // The property was found in a different context extension object. |
| 1527 // Set it if it is not a read-only property. | 1581 // Set it if it is not a read-only property. |
| 1528 if ((attributes & READ_ONLY) == 0) { | 1582 if ((attributes & READ_ONLY) == 0) { |
| 1529 Handle<Object> set = SetProperty(context_ext, name, value, attributes); | 1583 // Strict mode not needed (const disallowed in strict mode). |
| 1530 // Setting a property might throw an exception. Exceptions | 1584 RETURN_IF_EMPTY_HANDLE( |
| 1531 // are converted to empty handles in handle operations. We | 1585 isolate, |
| 1532 // need to convert back to exceptions here. | 1586 SetProperty(context_ext, name, value, attributes, kNonStrictMode)); |
| 1533 if (set.is_null()) { | |
| 1534 ASSERT(isolate->has_pending_exception()); | |
| 1535 return Failure::Exception(); | |
| 1536 } | |
| 1537 } | 1587 } |
| 1538 } | 1588 } |
| 1539 | 1589 |
| 1540 return *value; | 1590 return *value; |
| 1541 } | 1591 } |
| 1542 | 1592 |
| 1543 | 1593 |
| 1544 static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties( | 1594 static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties( |
| 1545 RUNTIME_CALLING_CONVENTION) { | 1595 RUNTIME_CALLING_CONVENTION) { |
| 1546 RUNTIME_GET_ISOLATE; | 1596 RUNTIME_GET_ISOLATE; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1698 Builtins::Name builtin_name) { | 1748 Builtins::Name builtin_name) { |
| 1699 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name); | 1749 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name); |
| 1700 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); | 1750 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); |
| 1701 Handle<JSFunction> optimized = | 1751 Handle<JSFunction> optimized = |
| 1702 isolate->factory()->NewFunction(key, | 1752 isolate->factory()->NewFunction(key, |
| 1703 JS_OBJECT_TYPE, | 1753 JS_OBJECT_TYPE, |
| 1704 JSObject::kHeaderSize, | 1754 JSObject::kHeaderSize, |
| 1705 code, | 1755 code, |
| 1706 false); | 1756 false); |
| 1707 optimized->shared()->DontAdaptArguments(); | 1757 optimized->shared()->DontAdaptArguments(); |
| 1708 SetProperty(holder, key, optimized, NONE); | 1758 SetProperty(holder, key, optimized, NONE, kStrictMode); |
| 1709 return optimized; | 1759 return optimized; |
| 1710 } | 1760 } |
| 1711 | 1761 |
| 1712 | 1762 |
| 1713 static MaybeObject* Runtime_SpecialArrayFunctions(RUNTIME_CALLING_CONVENTION) { | 1763 static MaybeObject* Runtime_SpecialArrayFunctions(RUNTIME_CALLING_CONVENTION) { |
| 1714 RUNTIME_GET_ISOLATE; | 1764 RUNTIME_GET_ISOLATE; |
| 1715 HandleScope scope(isolate); | 1765 HandleScope scope(isolate); |
| 1716 ASSERT(args.length() == 1); | 1766 ASSERT(args.length() == 1); |
| 1717 CONVERT_ARG_CHECKED(JSObject, holder, 0); | 1767 CONVERT_ARG_CHECKED(JSObject, holder, 0); |
| 1718 | 1768 |
| (...skipping 2124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3843 uint32_t index; | 3893 uint32_t index; |
| 3844 bool is_element = name->AsArrayIndex(&index); | 3894 bool is_element = name->AsArrayIndex(&index); |
| 3845 | 3895 |
| 3846 // Special case for elements if any of the flags are true. | 3896 // Special case for elements if any of the flags are true. |
| 3847 // If elements are in fast case we always implicitly assume that: | 3897 // If elements are in fast case we always implicitly assume that: |
| 3848 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. | 3898 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. |
| 3849 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) && | 3899 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) && |
| 3850 is_element) { | 3900 is_element) { |
| 3851 // Normalize the elements to enable attributes on the property. | 3901 // Normalize the elements to enable attributes on the property. |
| 3852 if (js_object->IsJSGlobalProxy()) { | 3902 if (js_object->IsJSGlobalProxy()) { |
| 3903 // We do not need to do access checks here since these has already |
| 3904 // been performed by the call to GetOwnProperty. |
| 3853 Handle<Object> proto(js_object->GetPrototype()); | 3905 Handle<Object> proto(js_object->GetPrototype()); |
| 3854 // If proxy is detached, ignore the assignment. Alternatively, | 3906 // If proxy is detached, ignore the assignment. Alternatively, |
| 3855 // we could throw an exception. | 3907 // we could throw an exception. |
| 3856 if (proto->IsNull()) return *obj_value; | 3908 if (proto->IsNull()) return *obj_value; |
| 3857 js_object = Handle<JSObject>::cast(proto); | 3909 js_object = Handle<JSObject>::cast(proto); |
| 3858 } | 3910 } |
| 3859 NormalizeElements(js_object); | 3911 NormalizeElements(js_object); |
| 3860 Handle<NumberDictionary> dictionary(js_object->element_dictionary()); | 3912 Handle<NumberDictionary> dictionary(js_object->element_dictionary()); |
| 3861 // Make sure that we never go back to fast case. | 3913 // Make sure that we never go back to fast case. |
| 3862 dictionary->set_requires_slow_elements(); | 3914 dictionary->set_requires_slow_elements(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3883 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); | 3935 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); |
| 3884 } | 3936 } |
| 3885 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); | 3937 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); |
| 3886 // Use IgnoreAttributes version since a readonly property may be | 3938 // Use IgnoreAttributes version since a readonly property may be |
| 3887 // overridden and SetProperty does not allow this. | 3939 // overridden and SetProperty does not allow this. |
| 3888 return js_object->SetLocalPropertyIgnoreAttributes(*name, | 3940 return js_object->SetLocalPropertyIgnoreAttributes(*name, |
| 3889 *obj_value, | 3941 *obj_value, |
| 3890 attr); | 3942 attr); |
| 3891 } | 3943 } |
| 3892 | 3944 |
| 3893 return Runtime::SetObjectProperty(isolate, js_object, name, obj_value, attr); | 3945 return Runtime::ForceSetObjectProperty(isolate, |
| 3946 js_object, |
| 3947 name, |
| 3948 obj_value, |
| 3949 attr); |
| 3894 } | 3950 } |
| 3895 | 3951 |
| 3896 | 3952 |
| 3897 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, | 3953 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
| 3898 Handle<Object> object, | 3954 Handle<Object> object, |
| 3899 Handle<Object> key, | 3955 Handle<Object> key, |
| 3900 Handle<Object> value, | 3956 Handle<Object> value, |
| 3901 PropertyAttributes attr) { | 3957 PropertyAttributes attr, |
| 3958 StrictModeFlag strict) { |
| 3902 HandleScope scope(isolate); | 3959 HandleScope scope(isolate); |
| 3903 | 3960 |
| 3904 if (object->IsUndefined() || object->IsNull()) { | 3961 if (object->IsUndefined() || object->IsNull()) { |
| 3905 Handle<Object> args[2] = { key, object }; | 3962 Handle<Object> args[2] = { key, object }; |
| 3906 Handle<Object> error = | 3963 Handle<Object> error = |
| 3907 isolate->factory()->NewTypeError("non_object_property_store", | 3964 isolate->factory()->NewTypeError("non_object_property_store", |
| 3908 HandleVector(args, 2)); | 3965 HandleVector(args, 2)); |
| 3909 return isolate->Throw(*error); | 3966 return isolate->Throw(*error); |
| 3910 } | 3967 } |
| 3911 | 3968 |
| 3912 // If the object isn't a JavaScript object, we ignore the store. | 3969 // If the object isn't a JavaScript object, we ignore the store. |
| 3913 if (!object->IsJSObject()) return *value; | 3970 if (!object->IsJSObject()) return *value; |
| 3914 | 3971 |
| 3915 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 3972 Handle<JSObject> js_object = Handle<JSObject>::cast(object); |
| 3916 | 3973 |
| 3917 // Check if the given key is an array index. | 3974 // Check if the given key is an array index. |
| 3918 uint32_t index; | 3975 uint32_t index; |
| 3919 if (key->ToArrayIndex(&index)) { | 3976 if (key->ToArrayIndex(&index)) { |
| 3920 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | 3977 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters |
| 3921 // of a string using [] notation. We need to support this too in | 3978 // of a string using [] notation. We need to support this too in |
| 3922 // JavaScript. | 3979 // JavaScript. |
| 3923 // In the case of a String object we just need to redirect the assignment to | 3980 // In the case of a String object we just need to redirect the assignment to |
| 3924 // the underlying string if the index is in range. Since the underlying | 3981 // the underlying string if the index is in range. Since the underlying |
| 3925 // string does nothing with the assignment then we can ignore such | 3982 // string does nothing with the assignment then we can ignore such |
| 3926 // assignments. | 3983 // assignments. |
| 3927 if (js_object->IsStringObjectWithCharacterAt(index)) { | 3984 if (js_object->IsStringObjectWithCharacterAt(index)) { |
| 3928 return *value; | 3985 return *value; |
| 3929 } | 3986 } |
| 3930 | 3987 |
| 3988 // TODO(1220): Implement SetElement strict mode. |
| 3931 Handle<Object> result = SetElement(js_object, index, value); | 3989 Handle<Object> result = SetElement(js_object, index, value); |
| 3932 if (result.is_null()) return Failure::Exception(); | 3990 if (result.is_null()) return Failure::Exception(); |
| 3933 return *value; | 3991 return *value; |
| 3934 } | 3992 } |
| 3935 | 3993 |
| 3936 if (key->IsString()) { | 3994 if (key->IsString()) { |
| 3937 Handle<Object> result; | 3995 Handle<Object> result; |
| 3938 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 3996 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
| 3939 result = SetElement(js_object, index, value); | 3997 result = SetElement(js_object, index, value); |
| 3940 } else { | 3998 } else { |
| 3941 Handle<String> key_string = Handle<String>::cast(key); | 3999 Handle<String> key_string = Handle<String>::cast(key); |
| 3942 key_string->TryFlatten(); | 4000 key_string->TryFlatten(); |
| 3943 result = SetProperty(js_object, key_string, value, attr); | 4001 result = SetProperty(js_object, key_string, value, attr, strict); |
| 3944 } | 4002 } |
| 3945 if (result.is_null()) return Failure::Exception(); | 4003 if (result.is_null()) return Failure::Exception(); |
| 3946 return *value; | 4004 return *value; |
| 3947 } | 4005 } |
| 3948 | 4006 |
| 3949 // Call-back into JavaScript to convert the key to a string. | 4007 // Call-back into JavaScript to convert the key to a string. |
| 3950 bool has_pending_exception = false; | 4008 bool has_pending_exception = false; |
| 3951 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 4009 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
| 3952 if (has_pending_exception) return Failure::Exception(); | 4010 if (has_pending_exception) return Failure::Exception(); |
| 3953 Handle<String> name = Handle<String>::cast(converted); | 4011 Handle<String> name = Handle<String>::cast(converted); |
| 3954 | 4012 |
| 3955 if (name->AsArrayIndex(&index)) { | 4013 if (name->AsArrayIndex(&index)) { |
| 4014 // TODO(1220): Implement SetElement strict mode. |
| 3956 return js_object->SetElement(index, *value); | 4015 return js_object->SetElement(index, *value); |
| 3957 } else { | 4016 } else { |
| 3958 return js_object->SetProperty(*name, *value, attr); | 4017 return js_object->SetProperty(*name, *value, attr, strict); |
| 3959 } | 4018 } |
| 3960 } | 4019 } |
| 3961 | 4020 |
| 3962 | 4021 |
| 3963 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, | 4022 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, |
| 3964 Handle<JSObject> js_object, | 4023 Handle<JSObject> js_object, |
| 3965 Handle<Object> key, | 4024 Handle<Object> key, |
| 3966 Handle<Object> value, | 4025 Handle<Object> value, |
| 3967 PropertyAttributes attr) { | 4026 PropertyAttributes attr) { |
| 3968 HandleScope scope(isolate); | 4027 HandleScope scope(isolate); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4043 } | 4102 } |
| 4044 | 4103 |
| 4045 key_string->TryFlatten(); | 4104 key_string->TryFlatten(); |
| 4046 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); | 4105 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); |
| 4047 } | 4106 } |
| 4048 | 4107 |
| 4049 | 4108 |
| 4050 static MaybeObject* Runtime_SetProperty(RUNTIME_CALLING_CONVENTION) { | 4109 static MaybeObject* Runtime_SetProperty(RUNTIME_CALLING_CONVENTION) { |
| 4051 RUNTIME_GET_ISOLATE; | 4110 RUNTIME_GET_ISOLATE; |
| 4052 NoHandleAllocation ha; | 4111 NoHandleAllocation ha; |
| 4053 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); | 4112 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); |
| 4054 | 4113 |
| 4055 Handle<Object> object = args.at<Object>(0); | 4114 Handle<Object> object = args.at<Object>(0); |
| 4056 Handle<Object> key = args.at<Object>(1); | 4115 Handle<Object> key = args.at<Object>(1); |
| 4057 Handle<Object> value = args.at<Object>(2); | 4116 Handle<Object> value = args.at<Object>(2); |
| 4117 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]); |
| 4118 RUNTIME_ASSERT( |
| 4119 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); |
| 4120 // Compute attributes. |
| 4121 PropertyAttributes attributes = |
| 4122 static_cast<PropertyAttributes>(unchecked_attributes); |
| 4058 | 4123 |
| 4059 // Compute attributes. | 4124 StrictModeFlag strict = kNonStrictMode; |
| 4060 PropertyAttributes attributes = NONE; | 4125 if (args.length() == 5) { |
| 4061 if (args.length() == 4) { | 4126 CONVERT_SMI_CHECKED(strict_unchecked, args[4]); |
| 4062 CONVERT_CHECKED(Smi, value_obj, args[3]); | 4127 RUNTIME_ASSERT(strict_unchecked == kStrictMode || |
| 4063 int unchecked_value = value_obj->value(); | 4128 strict_unchecked == kNonStrictMode); |
| 4064 // Only attribute bits should be set. | 4129 strict = static_cast<StrictModeFlag>(strict_unchecked); |
| 4065 RUNTIME_ASSERT( | |
| 4066 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
| 4067 attributes = static_cast<PropertyAttributes>(unchecked_value); | |
| 4068 } | 4130 } |
| 4069 return Runtime::SetObjectProperty(isolate, object, key, value, attributes); | 4131 |
| 4132 return Runtime::SetObjectProperty(isolate, |
| 4133 object, |
| 4134 key, |
| 4135 value, |
| 4136 attributes, |
| 4137 strict); |
| 4070 } | 4138 } |
| 4071 | 4139 |
| 4072 | 4140 |
| 4073 // Set a local property, even if it is READ_ONLY. If the property does not | 4141 // Set a local property, even if it is READ_ONLY. If the property does not |
| 4074 // exist, it will be added with attributes NONE. | 4142 // exist, it will be added with attributes NONE. |
| 4075 static MaybeObject* Runtime_IgnoreAttributesAndSetProperty( | 4143 static MaybeObject* Runtime_IgnoreAttributesAndSetProperty( |
| 4076 RUNTIME_CALLING_CONVENTION) { | 4144 RUNTIME_CALLING_CONVENTION) { |
| 4077 RUNTIME_GET_ISOLATE; | 4145 RUNTIME_GET_ISOLATE; |
| 4078 NoHandleAllocation ha; | 4146 NoHandleAllocation ha; |
| 4079 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); | 4147 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4091 } | 4159 } |
| 4092 | 4160 |
| 4093 return object-> | 4161 return object-> |
| 4094 SetLocalPropertyIgnoreAttributes(name, args[2], attributes); | 4162 SetLocalPropertyIgnoreAttributes(name, args[2], attributes); |
| 4095 } | 4163 } |
| 4096 | 4164 |
| 4097 | 4165 |
| 4098 static MaybeObject* Runtime_DeleteProperty(RUNTIME_CALLING_CONVENTION) { | 4166 static MaybeObject* Runtime_DeleteProperty(RUNTIME_CALLING_CONVENTION) { |
| 4099 RUNTIME_GET_ISOLATE; | 4167 RUNTIME_GET_ISOLATE; |
| 4100 NoHandleAllocation ha; | 4168 NoHandleAllocation ha; |
| 4101 ASSERT(args.length() == 2); | 4169 ASSERT(args.length() == 3); |
| 4102 | 4170 |
| 4103 CONVERT_CHECKED(JSObject, object, args[0]); | 4171 CONVERT_CHECKED(JSObject, object, args[0]); |
| 4104 CONVERT_CHECKED(String, key, args[1]); | 4172 CONVERT_CHECKED(String, key, args[1]); |
| 4105 return object->DeleteProperty(key, JSObject::NORMAL_DELETION); | 4173 CONVERT_SMI_CHECKED(strict, args[2]); |
| 4174 return object->DeleteProperty(key, (strict == kStrictMode) |
| 4175 ? JSObject::STRICT_DELETION |
| 4176 : JSObject::NORMAL_DELETION); |
| 4106 } | 4177 } |
| 4107 | 4178 |
| 4108 | 4179 |
| 4109 static Object* HasLocalPropertyImplementation(Isolate* isolate, | 4180 static Object* HasLocalPropertyImplementation(Isolate* isolate, |
| 4110 Handle<JSObject> object, | 4181 Handle<JSObject> object, |
| 4111 Handle<String> key) { | 4182 Handle<String> key) { |
| 4112 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value(); | 4183 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value(); |
| 4113 // Handle hidden prototypes. If there's a hidden prototype above this thing | 4184 // Handle hidden prototypes. If there's a hidden prototype above this thing |
| 4114 // then we have to check it for properties, because they are supposed to | 4185 // then we have to check it for properties, because they are supposed to |
| 4115 // look like they are on this object. | 4186 // look like they are on this object. |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4410 return isolate->heap()->undefined_value(); | 4481 return isolate->heap()->undefined_value(); |
| 4411 } | 4482 } |
| 4412 | 4483 |
| 4413 | 4484 |
| 4414 static MaybeObject* Runtime_LocalKeys(RUNTIME_CALLING_CONVENTION) { | 4485 static MaybeObject* Runtime_LocalKeys(RUNTIME_CALLING_CONVENTION) { |
| 4415 RUNTIME_GET_ISOLATE; | 4486 RUNTIME_GET_ISOLATE; |
| 4416 ASSERT_EQ(args.length(), 1); | 4487 ASSERT_EQ(args.length(), 1); |
| 4417 CONVERT_CHECKED(JSObject, raw_object, args[0]); | 4488 CONVERT_CHECKED(JSObject, raw_object, args[0]); |
| 4418 HandleScope scope(isolate); | 4489 HandleScope scope(isolate); |
| 4419 Handle<JSObject> object(raw_object); | 4490 Handle<JSObject> object(raw_object); |
| 4491 |
| 4492 if (object->IsJSGlobalProxy()) { |
| 4493 // Do access checks before going to the global object. |
| 4494 if (object->IsAccessCheckNeeded() && |
| 4495 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), |
| 4496 v8::ACCESS_KEYS)) { |
| 4497 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); |
| 4498 return *isolate->factory()->NewJSArray(0); |
| 4499 } |
| 4500 |
| 4501 Handle<Object> proto(object->GetPrototype()); |
| 4502 // If proxy is detached we simply return an empty array. |
| 4503 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); |
| 4504 object = Handle<JSObject>::cast(proto); |
| 4505 } |
| 4506 |
| 4420 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, | 4507 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, |
| 4421 LOCAL_ONLY); | 4508 LOCAL_ONLY); |
| 4422 // Some fast paths through GetKeysInFixedArrayFor reuse a cached | 4509 // Some fast paths through GetKeysInFixedArrayFor reuse a cached |
| 4423 // property array and since the result is mutable we have to create | 4510 // property array and since the result is mutable we have to create |
| 4424 // a fresh clone on each invocation. | 4511 // a fresh clone on each invocation. |
| 4425 int length = contents->length(); | 4512 int length = contents->length(); |
| 4426 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); | 4513 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); |
| 4427 for (int i = 0; i < length; i++) { | 4514 for (int i = 0; i < length; i++) { |
| 4428 Object* entry = contents->get(i); | 4515 Object* entry = contents->get(i); |
| 4429 if (entry->IsString()) { | 4516 if (entry->IsString()) { |
| (...skipping 1621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6051 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 6138 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
| 6052 StringBuilderConcatHelper(special, | 6139 StringBuilderConcatHelper(special, |
| 6053 answer->GetChars(), | 6140 answer->GetChars(), |
| 6054 fixed_array, | 6141 fixed_array, |
| 6055 array_length); | 6142 array_length); |
| 6056 return answer; | 6143 return answer; |
| 6057 } | 6144 } |
| 6058 } | 6145 } |
| 6059 | 6146 |
| 6060 | 6147 |
| 6148 static MaybeObject* Runtime_StringBuilderJoin(RUNTIME_CALLING_CONVENTION) { |
| 6149 RUNTIME_GET_ISOLATE; |
| 6150 NoHandleAllocation ha; |
| 6151 ASSERT(args.length() == 3); |
| 6152 CONVERT_CHECKED(JSArray, array, args[0]); |
| 6153 if (!args[1]->IsSmi()) { |
| 6154 isolate->context()->mark_out_of_memory(); |
| 6155 return Failure::OutOfMemoryException(); |
| 6156 } |
| 6157 int array_length = Smi::cast(args[1])->value(); |
| 6158 CONVERT_CHECKED(String, separator, args[2]); |
| 6159 |
| 6160 if (!array->HasFastElements()) { |
| 6161 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); |
| 6162 } |
| 6163 FixedArray* fixed_array = FixedArray::cast(array->elements()); |
| 6164 if (fixed_array->length() < array_length) { |
| 6165 array_length = fixed_array->length(); |
| 6166 } |
| 6167 |
| 6168 if (array_length == 0) { |
| 6169 return isolate->heap()->empty_string(); |
| 6170 } else if (array_length == 1) { |
| 6171 Object* first = fixed_array->get(0); |
| 6172 if (first->IsString()) return first; |
| 6173 } |
| 6174 |
| 6175 int separator_length = separator->length(); |
| 6176 int max_nof_separators = |
| 6177 (String::kMaxLength + separator_length - 1) / separator_length; |
| 6178 if (max_nof_separators < (array_length - 1)) { |
| 6179 isolate->context()->mark_out_of_memory(); |
| 6180 return Failure::OutOfMemoryException(); |
| 6181 } |
| 6182 int length = (array_length - 1) * separator_length; |
| 6183 for (int i = 0; i < array_length; i++) { |
| 6184 Object* element_obj = fixed_array->get(i); |
| 6185 if (!element_obj->IsString()) { |
| 6186 // TODO(1161): handle this case. |
| 6187 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); |
| 6188 } |
| 6189 String* element = String::cast(element_obj); |
| 6190 int increment = element->length(); |
| 6191 if (increment > String::kMaxLength - length) { |
| 6192 isolate->context()->mark_out_of_memory(); |
| 6193 return Failure::OutOfMemoryException(); |
| 6194 } |
| 6195 length += increment; |
| 6196 } |
| 6197 |
| 6198 Object* object; |
| 6199 { MaybeObject* maybe_object = |
| 6200 isolate->heap()->AllocateRawTwoByteString(length); |
| 6201 if (!maybe_object->ToObject(&object)) return maybe_object; |
| 6202 } |
| 6203 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
| 6204 |
| 6205 uc16* sink = answer->GetChars(); |
| 6206 #ifdef DEBUG |
| 6207 uc16* end = sink + length; |
| 6208 #endif |
| 6209 |
| 6210 String* first = String::cast(fixed_array->get(0)); |
| 6211 int first_length = first->length(); |
| 6212 String::WriteToFlat(first, sink, 0, first_length); |
| 6213 sink += first_length; |
| 6214 |
| 6215 for (int i = 1; i < array_length; i++) { |
| 6216 ASSERT(sink + separator_length <= end); |
| 6217 String::WriteToFlat(separator, sink, 0, separator_length); |
| 6218 sink += separator_length; |
| 6219 |
| 6220 String* element = String::cast(fixed_array->get(i)); |
| 6221 int element_length = element->length(); |
| 6222 ASSERT(sink + element_length <= end); |
| 6223 String::WriteToFlat(element, sink, 0, element_length); |
| 6224 sink += element_length; |
| 6225 } |
| 6226 ASSERT(sink == end); |
| 6227 |
| 6228 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead. |
| 6229 return answer; |
| 6230 } |
| 6231 |
| 6232 |
| 6061 static MaybeObject* Runtime_NumberOr(RUNTIME_CALLING_CONVENTION) { | 6233 static MaybeObject* Runtime_NumberOr(RUNTIME_CALLING_CONVENTION) { |
| 6062 RUNTIME_GET_ISOLATE; | 6234 RUNTIME_GET_ISOLATE; |
| 6063 NoHandleAllocation ha; | 6235 NoHandleAllocation ha; |
| 6064 ASSERT(args.length() == 2); | 6236 ASSERT(args.length() == 2); |
| 6065 | 6237 |
| 6066 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 6238 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); |
| 6067 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 6239 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); |
| 6068 return isolate->heap()->NumberFromInt32(x | y); | 6240 return isolate->heap()->NumberFromInt32(x | y); |
| 6069 } | 6241 } |
| 6070 | 6242 |
| (...skipping 1054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7125 if (!function->has_initial_map() && | 7297 if (!function->has_initial_map() && |
| 7126 shared->IsInobjectSlackTrackingInProgress()) { | 7298 shared->IsInobjectSlackTrackingInProgress()) { |
| 7127 // The tracking is already in progress for another function. We can only | 7299 // The tracking is already in progress for another function. We can only |
| 7128 // track one initial_map at a time, so we force the completion before the | 7300 // track one initial_map at a time, so we force the completion before the |
| 7129 // function is called as a constructor for the first time. | 7301 // function is called as a constructor for the first time. |
| 7130 shared->CompleteInobjectSlackTracking(); | 7302 shared->CompleteInobjectSlackTracking(); |
| 7131 } | 7303 } |
| 7132 | 7304 |
| 7133 bool first_allocation = !shared->live_objects_may_exist(); | 7305 bool first_allocation = !shared->live_objects_may_exist(); |
| 7134 Handle<JSObject> result = isolate->factory()->NewJSObject(function); | 7306 Handle<JSObject> result = isolate->factory()->NewJSObject(function); |
| 7307 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 7135 // Delay setting the stub if inobject slack tracking is in progress. | 7308 // Delay setting the stub if inobject slack tracking is in progress. |
| 7136 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) { | 7309 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) { |
| 7137 TrySettingInlineConstructStub(isolate, function); | 7310 TrySettingInlineConstructStub(isolate, function); |
| 7138 } | 7311 } |
| 7139 | 7312 |
| 7140 isolate->counters()->constructed_objects()->Increment(); | 7313 isolate->counters()->constructed_objects()->Increment(); |
| 7141 isolate->counters()->constructed_objects_runtime()->Increment(); | 7314 isolate->counters()->constructed_objects_runtime()->Increment(); |
| 7142 | 7315 |
| 7143 return *result; | 7316 return *result; |
| 7144 } | 7317 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7201 if (FLAG_trace_opt) { | 7374 if (FLAG_trace_opt) { |
| 7202 PrintF("[failed to optimize "); | 7375 PrintF("[failed to optimize "); |
| 7203 function->PrintName(); | 7376 function->PrintName(); |
| 7204 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", | 7377 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", |
| 7205 function->shared()->code()->optimizable() ? "T" : "F", | 7378 function->shared()->code()->optimizable() ? "T" : "F", |
| 7206 isolate->debug()->has_break_points() ? "T" : "F"); | 7379 isolate->debug()->has_break_points() ? "T" : "F"); |
| 7207 } | 7380 } |
| 7208 function->ReplaceCode(function->shared()->code()); | 7381 function->ReplaceCode(function->shared()->code()); |
| 7209 return function->code(); | 7382 return function->code(); |
| 7210 } | 7383 } |
| 7211 if (CompileOptimized(function, AstNode::kNoNumber)) { | 7384 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) { |
| 7212 return function->code(); | 7385 return function->code(); |
| 7213 } | 7386 } |
| 7214 if (FLAG_trace_opt) { | 7387 if (FLAG_trace_opt) { |
| 7215 PrintF("[failed to optimize "); | 7388 PrintF("[failed to optimize "); |
| 7216 function->PrintName(); | 7389 function->PrintName(); |
| 7217 PrintF(": optimized compilation failed]\n"); | 7390 PrintF(": optimized compilation failed]\n"); |
| 7218 } | 7391 } |
| 7219 function->ReplaceCode(function->shared()->code()); | 7392 function->ReplaceCode(function->shared()->code()); |
| 7220 return Failure::Exception(); | 7393 return function->code(); |
| 7221 } | 7394 } |
| 7222 | 7395 |
| 7223 | 7396 |
| 7224 static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) { | 7397 static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) { |
| 7225 RUNTIME_GET_ISOLATE; | 7398 RUNTIME_GET_ISOLATE; |
| 7226 HandleScope scope(isolate); | 7399 HandleScope scope(isolate); |
| 7227 ASSERT(args.length() == 1); | 7400 ASSERT(args.length() == 1); |
| 7228 RUNTIME_ASSERT(args[0]->IsSmi()); | 7401 RUNTIME_ASSERT(args[0]->IsSmi()); |
| 7229 Deoptimizer::BailoutType type = | 7402 Deoptimizer::BailoutType type = |
| 7230 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value()); | 7403 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value()); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7375 ASSERT(ast_id != AstNode::kNoNumber); | 7548 ASSERT(ast_id != AstNode::kNoNumber); |
| 7376 if (FLAG_trace_osr) { | 7549 if (FLAG_trace_osr) { |
| 7377 PrintF("[replacing on-stack at AST id %d in ", ast_id); | 7550 PrintF("[replacing on-stack at AST id %d in ", ast_id); |
| 7378 function->PrintName(); | 7551 function->PrintName(); |
| 7379 PrintF("]\n"); | 7552 PrintF("]\n"); |
| 7380 } | 7553 } |
| 7381 | 7554 |
| 7382 // Try to compile the optimized code. A true return value from | 7555 // Try to compile the optimized code. A true return value from |
| 7383 // CompileOptimized means that compilation succeeded, not necessarily | 7556 // CompileOptimized means that compilation succeeded, not necessarily |
| 7384 // that optimization succeeded. | 7557 // that optimization succeeded. |
| 7385 if (CompileOptimized(function, ast_id) && function->IsOptimized()) { | 7558 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) && |
| 7559 function->IsOptimized()) { |
| 7386 DeoptimizationInputData* data = DeoptimizationInputData::cast( | 7560 DeoptimizationInputData* data = DeoptimizationInputData::cast( |
| 7387 function->code()->deoptimization_data()); | 7561 function->code()->deoptimization_data()); |
| 7388 if (data->OsrPcOffset()->value() >= 0) { | 7562 if (data->OsrPcOffset()->value() >= 0) { |
| 7389 if (FLAG_trace_osr) { | 7563 if (FLAG_trace_osr) { |
| 7390 PrintF("[on-stack replacement offset %d in optimized code]\n", | 7564 PrintF("[on-stack replacement offset %d in optimized code]\n", |
| 7391 data->OsrPcOffset()->value()); | 7565 data->OsrPcOffset()->value()); |
| 7392 } | 7566 } |
| 7393 ASSERT(data->OsrAstId()->value() == ast_id); | 7567 ASSERT(data->OsrAstId()->value() == ast_id); |
| 7394 } else { | 7568 } else { |
| 7395 // We may never generate the desired OSR entry if we emit an | 7569 // We may never generate the desired OSR entry if we emit an |
| (...skipping 22 matching lines...) Expand all Loading... |
| 7418 // Allow OSR only at nesting level zero again. | 7592 // Allow OSR only at nesting level zero again. |
| 7419 unoptimized->set_allow_osr_at_loop_nesting_level(0); | 7593 unoptimized->set_allow_osr_at_loop_nesting_level(0); |
| 7420 | 7594 |
| 7421 // If the optimization attempt succeeded, return the AST id tagged as a | 7595 // If the optimization attempt succeeded, return the AST id tagged as a |
| 7422 // smi. This tells the builtin that we need to translate the unoptimized | 7596 // smi. This tells the builtin that we need to translate the unoptimized |
| 7423 // frame to an optimized one. | 7597 // frame to an optimized one. |
| 7424 if (succeeded) { | 7598 if (succeeded) { |
| 7425 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); | 7599 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); |
| 7426 return Smi::FromInt(ast_id); | 7600 return Smi::FromInt(ast_id); |
| 7427 } else { | 7601 } else { |
| 7602 if (function->IsMarkedForLazyRecompilation()) { |
| 7603 function->ReplaceCode(function->shared()->code()); |
| 7604 } |
| 7428 return Smi::FromInt(-1); | 7605 return Smi::FromInt(-1); |
| 7429 } | 7606 } |
| 7430 } | 7607 } |
| 7431 | 7608 |
| 7432 | 7609 |
| 7433 static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) { | 7610 static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) { |
| 7434 RUNTIME_GET_ISOLATE; | 7611 RUNTIME_GET_ISOLATE; |
| 7435 HandleScope scope(isolate); | 7612 HandleScope scope(isolate); |
| 7436 ASSERT(args.length() == 1); | 7613 ASSERT(args.length() == 1); |
| 7437 RUNTIME_ASSERT(!args[0]->IsJSFunction()); | 7614 RUNTIME_ASSERT(!args[0]->IsJSFunction()); |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7686 static ObjectPair Runtime_LoadContextSlotNoReferenceError( | 7863 static ObjectPair Runtime_LoadContextSlotNoReferenceError( |
| 7687 RUNTIME_CALLING_CONVENTION) { | 7864 RUNTIME_CALLING_CONVENTION) { |
| 7688 RUNTIME_GET_ISOLATE; | 7865 RUNTIME_GET_ISOLATE; |
| 7689 return LoadContextSlotHelper(args, isolate, false); | 7866 return LoadContextSlotHelper(args, isolate, false); |
| 7690 } | 7867 } |
| 7691 | 7868 |
| 7692 | 7869 |
| 7693 static MaybeObject* Runtime_StoreContextSlot(RUNTIME_CALLING_CONVENTION) { | 7870 static MaybeObject* Runtime_StoreContextSlot(RUNTIME_CALLING_CONVENTION) { |
| 7694 RUNTIME_GET_ISOLATE; | 7871 RUNTIME_GET_ISOLATE; |
| 7695 HandleScope scope(isolate); | 7872 HandleScope scope(isolate); |
| 7696 ASSERT(args.length() == 3); | 7873 ASSERT(args.length() == 4); |
| 7697 | 7874 |
| 7698 Handle<Object> value(args[0], isolate); | 7875 Handle<Object> value(args[0], isolate); |
| 7699 CONVERT_ARG_CHECKED(Context, context, 1); | 7876 CONVERT_ARG_CHECKED(Context, context, 1); |
| 7700 CONVERT_ARG_CHECKED(String, name, 2); | 7877 CONVERT_ARG_CHECKED(String, name, 2); |
| 7878 CONVERT_SMI_CHECKED(strict_unchecked, args[3]); |
| 7879 RUNTIME_ASSERT(strict_unchecked == kStrictMode || |
| 7880 strict_unchecked == kNonStrictMode); |
| 7881 StrictModeFlag strict = static_cast<StrictModeFlag>(strict_unchecked); |
| 7882 |
| 7701 | 7883 |
| 7702 int index; | 7884 int index; |
| 7703 PropertyAttributes attributes; | 7885 PropertyAttributes attributes; |
| 7704 ContextLookupFlags flags = FOLLOW_CHAINS; | 7886 ContextLookupFlags flags = FOLLOW_CHAINS; |
| 7705 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); | 7887 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); |
| 7706 | 7888 |
| 7707 if (index >= 0) { | 7889 if (index >= 0) { |
| 7708 if (holder->IsContext()) { | 7890 if (holder->IsContext()) { |
| 7709 // Ignore if read_only variable. | 7891 // Ignore if read_only variable. |
| 7710 if ((attributes & READ_ONLY) == 0) { | 7892 if ((attributes & READ_ONLY) == 0) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 7734 // The property was not found. It needs to be stored in the global context. | 7916 // The property was not found. It needs to be stored in the global context. |
| 7735 ASSERT(attributes == ABSENT); | 7917 ASSERT(attributes == ABSENT); |
| 7736 attributes = NONE; | 7918 attributes = NONE; |
| 7737 context_ext = Handle<JSObject>(isolate->context()->global()); | 7919 context_ext = Handle<JSObject>(isolate->context()->global()); |
| 7738 } | 7920 } |
| 7739 | 7921 |
| 7740 // Set the property, but ignore if read_only variable on the context | 7922 // Set the property, but ignore if read_only variable on the context |
| 7741 // extension object itself. | 7923 // extension object itself. |
| 7742 if ((attributes & READ_ONLY) == 0 || | 7924 if ((attributes & READ_ONLY) == 0 || |
| 7743 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { | 7925 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { |
| 7744 Handle<Object> result = SetProperty(context_ext, name, value, NONE); | 7926 RETURN_IF_EMPTY_HANDLE(isolate, |
| 7745 if (result.is_null()) { | 7927 SetProperty(context_ext, name, value, NONE, strict)); |
| 7746 // Failure::Exception is converted to a null handle in the | 7928 } else if (strict == kStrictMode && (attributes & READ_ONLY) != 0) { |
| 7747 // handle-based methods such as SetProperty. We therefore need | 7929 // Setting read only property in strict mode. |
| 7748 // to convert null handles back to exceptions. | 7930 Handle<Object> error = |
| 7749 ASSERT(isolate->has_pending_exception()); | 7931 isolate->factory()->NewTypeError( |
| 7750 return Failure::Exception(); | 7932 "strict_cannot_assign", HandleVector(&name, 1)); |
| 7751 } | 7933 return isolate->Throw(*error); |
| 7752 } | 7934 } |
| 7753 return *value; | 7935 return *value; |
| 7754 } | 7936 } |
| 7755 | 7937 |
| 7756 | 7938 |
| 7757 static MaybeObject* Runtime_Throw(RUNTIME_CALLING_CONVENTION) { | 7939 static MaybeObject* Runtime_Throw(RUNTIME_CALLING_CONVENTION) { |
| 7758 RUNTIME_GET_ISOLATE; | 7940 RUNTIME_GET_ISOLATE; |
| 7759 HandleScope scope(isolate); | 7941 HandleScope scope(isolate); |
| 7760 ASSERT(args.length() == 1); | 7942 ASSERT(args.length() == 1); |
| 7761 | 7943 |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8088 isolate->factory()->NewFunctionFromSharedFunctionInfo( | 8270 isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| 8089 shared, Handle<Context>(isolate->context()), NOT_TENURED); | 8271 shared, Handle<Context>(isolate->context()), NOT_TENURED); |
| 8090 return MakePair(*compiled, *receiver); | 8272 return MakePair(*compiled, *receiver); |
| 8091 } | 8273 } |
| 8092 | 8274 |
| 8093 | 8275 |
| 8094 static ObjectPair Runtime_ResolvePossiblyDirectEval( | 8276 static ObjectPair Runtime_ResolvePossiblyDirectEval( |
| 8095 RUNTIME_CALLING_CONVENTION) { | 8277 RUNTIME_CALLING_CONVENTION) { |
| 8096 RUNTIME_GET_ISOLATE; | 8278 RUNTIME_GET_ISOLATE; |
| 8097 ASSERT(args.length() == 4); | 8279 ASSERT(args.length() == 4); |
| 8098 if (!args[0]->IsJSFunction()) { | |
| 8099 return MakePair(isolate->ThrowIllegalOperation(), NULL); | |
| 8100 } | |
| 8101 | 8280 |
| 8102 HandleScope scope(isolate); | 8281 HandleScope scope(isolate); |
| 8103 Handle<JSFunction> callee = args.at<JSFunction>(0); | 8282 Handle<Object> callee = args.at<Object>(0); |
| 8104 Handle<Object> receiver; // Will be overwritten. | 8283 Handle<Object> receiver; // Will be overwritten. |
| 8105 | 8284 |
| 8106 // Compute the calling context. | 8285 // Compute the calling context. |
| 8107 Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 8286 Handle<Context> context = Handle<Context>(isolate->context(), isolate); |
| 8108 #ifdef DEBUG | 8287 #ifdef DEBUG |
| 8109 // Make sure Isolate::context() agrees with the old code that traversed | 8288 // Make sure Isolate::context() agrees with the old code that traversed |
| 8110 // the stack frames to compute the context. | 8289 // the stack frames to compute the context. |
| 8111 StackFrameLocator locator; | 8290 StackFrameLocator locator; |
| 8112 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 8291 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 8113 ASSERT(Context::cast(frame->context()) == *context); | 8292 ASSERT(Context::cast(frame->context()) == *context); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8169 args.at<Object>(2), | 8348 args.at<Object>(2), |
| 8170 static_cast<StrictModeFlag>( | 8349 static_cast<StrictModeFlag>( |
| 8171 Smi::cast(args[3])->value())); | 8350 Smi::cast(args[3])->value())); |
| 8172 } | 8351 } |
| 8173 | 8352 |
| 8174 | 8353 |
| 8175 static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup( | 8354 static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup( |
| 8176 RUNTIME_CALLING_CONVENTION) { | 8355 RUNTIME_CALLING_CONVENTION) { |
| 8177 RUNTIME_GET_ISOLATE; | 8356 RUNTIME_GET_ISOLATE; |
| 8178 ASSERT(args.length() == 4); | 8357 ASSERT(args.length() == 4); |
| 8179 if (!args[0]->IsJSFunction()) { | |
| 8180 return MakePair(isolate->ThrowIllegalOperation(), NULL); | |
| 8181 } | |
| 8182 | 8358 |
| 8183 HandleScope scope(isolate); | 8359 HandleScope scope(isolate); |
| 8184 Handle<JSFunction> callee = args.at<JSFunction>(0); | 8360 Handle<Object> callee = args.at<Object>(0); |
| 8185 | 8361 |
| 8186 // 'eval' is bound in the global context, but it may have been overwritten. | 8362 // 'eval' is bound in the global context, but it may have been overwritten. |
| 8187 // Compare it to the builtin 'GlobalEval' function to make sure. | 8363 // Compare it to the builtin 'GlobalEval' function to make sure. |
| 8188 if (*callee != isolate->global_context()->global_eval_fun() || | 8364 if (*callee != isolate->global_context()->global_eval_fun() || |
| 8189 !args[1]->IsString()) { | 8365 !args[1]->IsString()) { |
| 8190 return MakePair(*callee, | 8366 return MakePair(*callee, |
| 8191 isolate->context()->global()->global_receiver()); | 8367 isolate->context()->global()->global_receiver()); |
| 8192 } | 8368 } |
| 8193 | 8369 |
| 8194 ASSERT(args[3]->IsSmi()); | 8370 ASSERT(args[3]->IsSmi()); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8270 * or a dictionary for sparse array. Since Dictionary is a subtype | 8446 * or a dictionary for sparse array. Since Dictionary is a subtype |
| 8271 * of FixedArray, the class can be used by both fast and slow cases. | 8447 * of FixedArray, the class can be used by both fast and slow cases. |
| 8272 * The second parameter of the constructor, fast_elements, specifies | 8448 * The second parameter of the constructor, fast_elements, specifies |
| 8273 * whether the storage is a FixedArray or Dictionary. | 8449 * whether the storage is a FixedArray or Dictionary. |
| 8274 * | 8450 * |
| 8275 * An index limit is used to deal with the situation that a result array | 8451 * An index limit is used to deal with the situation that a result array |
| 8276 * length overflows 32-bit non-negative integer. | 8452 * length overflows 32-bit non-negative integer. |
| 8277 */ | 8453 */ |
| 8278 class ArrayConcatVisitor { | 8454 class ArrayConcatVisitor { |
| 8279 public: | 8455 public: |
| 8280 ArrayConcatVisitor(Handle<FixedArray> storage, | 8456 ArrayConcatVisitor(Isolate* isolate, |
| 8281 uint32_t index_limit, | 8457 Handle<FixedArray> storage, |
| 8282 bool fast_elements) : | 8458 bool fast_elements) : |
| 8283 storage_(storage), index_limit_(index_limit), | 8459 isolate_(isolate), |
| 8284 index_offset_(0), fast_elements_(fast_elements) { } | 8460 storage_(Handle<FixedArray>::cast( |
| 8461 isolate->global_handles()->Create(*storage))), |
| 8462 index_offset_(0u), |
| 8463 fast_elements_(fast_elements) { } |
| 8464 |
| 8465 ~ArrayConcatVisitor() { |
| 8466 clear_storage(); |
| 8467 } |
| 8285 | 8468 |
| 8286 void visit(uint32_t i, Handle<Object> elm) { | 8469 void visit(uint32_t i, Handle<Object> elm) { |
| 8287 if (i >= index_limit_ - index_offset_) return; | 8470 if (i >= JSObject::kMaxElementCount - index_offset_) return; |
| 8288 uint32_t index = index_offset_ + i; | 8471 uint32_t index = index_offset_ + i; |
| 8289 | 8472 |
| 8290 if (fast_elements_) { | 8473 if (fast_elements_) { |
| 8291 ASSERT(index < static_cast<uint32_t>(storage_->length())); | 8474 if (index < static_cast<uint32_t>(storage_->length())) { |
| 8292 storage_->set(index, *elm); | 8475 storage_->set(index, *elm); |
| 8293 | 8476 return; |
| 8294 } else { | 8477 } |
| 8295 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); | 8478 // Our initial estimate of length was foiled, possibly by |
| 8296 Handle<NumberDictionary> result = | 8479 // getters on the arrays increasing the length of later arrays |
| 8297 storage_->GetIsolate()->factory()->DictionaryAtNumberPut(dict, | 8480 // during iteration. |
| 8298 index, | 8481 // This shouldn't happen in anything but pathological cases. |
| 8299 elm); | 8482 SetDictionaryMode(index); |
| 8300 if (!result.is_identical_to(dict)) | 8483 // Fall-through to dictionary mode. |
| 8301 storage_ = result; | 8484 } |
| 8302 } | 8485 ASSERT(!fast_elements_); |
| 8303 } | 8486 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_)); |
| 8487 Handle<NumberDictionary> result = |
| 8488 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); |
| 8489 if (!result.is_identical_to(dict)) { |
| 8490 // Dictionary needed to grow. |
| 8491 clear_storage(); |
| 8492 set_storage(*result); |
| 8493 } |
| 8494 } |
| 8304 | 8495 |
| 8305 void increase_index_offset(uint32_t delta) { | 8496 void increase_index_offset(uint32_t delta) { |
| 8306 if (index_limit_ - index_offset_ < delta) { | 8497 if (JSObject::kMaxElementCount - index_offset_ < delta) { |
| 8307 index_offset_ = index_limit_; | 8498 index_offset_ = JSObject::kMaxElementCount; |
| 8308 } else { | 8499 } else { |
| 8309 index_offset_ += delta; | 8500 index_offset_ += delta; |
| 8310 } | 8501 } |
| 8311 } | 8502 } |
| 8312 | 8503 |
| 8313 Handle<FixedArray> storage() { return storage_; } | 8504 Handle<JSArray> ToArray() { |
| 8505 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); |
| 8506 Handle<Object> length = |
| 8507 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); |
| 8508 Handle<Map> map; |
| 8509 if (fast_elements_) { |
| 8510 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map())); |
| 8511 } else { |
| 8512 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map())); |
| 8513 } |
| 8514 array->set_map(*map); |
| 8515 array->set_length(*length); |
| 8516 array->set_elements(*storage_); |
| 8517 return array; |
| 8518 } |
| 8314 | 8519 |
| 8315 private: | 8520 private: |
| 8316 Handle<FixedArray> storage_; | 8521 // Convert storage to dictionary mode. |
| 8317 // Limit on the accepted indices. Elements with indices larger than the | 8522 void SetDictionaryMode(uint32_t index) { |
| 8318 // limit are ignored by the visitor. | 8523 ASSERT(fast_elements_); |
| 8319 uint32_t index_limit_; | 8524 Handle<FixedArray> current_storage(*storage_); |
| 8320 // Index after last seen index. Always less than or equal to index_limit_. | 8525 Handle<NumberDictionary> slow_storage( |
| 8526 isolate_->factory()->NewNumberDictionary(current_storage->length())); |
| 8527 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); |
| 8528 for (uint32_t i = 0; i < current_length; i++) { |
| 8529 HandleScope loop_scope; |
| 8530 Handle<Object> element(current_storage->get(i)); |
| 8531 if (!element->IsTheHole()) { |
| 8532 Handle<NumberDictionary> new_storage = |
| 8533 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); |
| 8534 if (!new_storage.is_identical_to(slow_storage)) { |
| 8535 slow_storage = loop_scope.CloseAndEscape(new_storage); |
| 8536 } |
| 8537 } |
| 8538 } |
| 8539 clear_storage(); |
| 8540 set_storage(*slow_storage); |
| 8541 fast_elements_ = false; |
| 8542 } |
| 8543 |
| 8544 inline void clear_storage() { |
| 8545 isolate_->global_handles()->Destroy( |
| 8546 Handle<Object>::cast(storage_).location()); |
| 8547 } |
| 8548 |
| 8549 inline void set_storage(FixedArray* storage) { |
| 8550 storage_ = Handle<FixedArray>::cast( |
| 8551 isolate_->global_handles()->Create(storage)); |
| 8552 } |
| 8553 |
| 8554 Isolate* isolate_; |
| 8555 Handle<FixedArray> storage_; // Always a global handle. |
| 8556 // Index after last seen index. Always less than or equal to |
| 8557 // JSObject::kMaxElementCount. |
| 8321 uint32_t index_offset_; | 8558 uint32_t index_offset_; |
| 8322 const bool fast_elements_; | 8559 bool fast_elements_; |
| 8323 }; | 8560 }; |
| 8324 | 8561 |
| 8325 | 8562 |
| 8563 static uint32_t EstimateElementCount(Handle<JSArray> array) { |
| 8564 uint32_t length = static_cast<uint32_t>(array->length()->Number()); |
| 8565 int element_count = 0; |
| 8566 switch (array->GetElementsKind()) { |
| 8567 case JSObject::FAST_ELEMENTS: { |
| 8568 // Fast elements can't have lengths that are not representable by |
| 8569 // a 32-bit signed integer. |
| 8570 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); |
| 8571 int fast_length = static_cast<int>(length); |
| 8572 Handle<FixedArray> elements(FixedArray::cast(array->elements())); |
| 8573 for (int i = 0; i < fast_length; i++) { |
| 8574 if (!elements->get(i)->IsTheHole()) element_count++; |
| 8575 } |
| 8576 break; |
| 8577 } |
| 8578 case JSObject::DICTIONARY_ELEMENTS: { |
| 8579 Handle<NumberDictionary> dictionary( |
| 8580 NumberDictionary::cast(array->elements())); |
| 8581 int capacity = dictionary->Capacity(); |
| 8582 for (int i = 0; i < capacity; i++) { |
| 8583 Handle<Object> key(dictionary->KeyAt(i)); |
| 8584 if (dictionary->IsKey(*key)) { |
| 8585 element_count++; |
| 8586 } |
| 8587 } |
| 8588 break; |
| 8589 } |
| 8590 default: |
| 8591 // External arrays are always dense. |
| 8592 return length; |
| 8593 } |
| 8594 // As an estimate, we assume that the prototype doesn't contain any |
| 8595 // inherited elements. |
| 8596 return element_count; |
| 8597 } |
| 8598 |
| 8599 |
| 8600 |
| 8326 template<class ExternalArrayClass, class ElementType> | 8601 template<class ExternalArrayClass, class ElementType> |
| 8327 static uint32_t IterateExternalArrayElements(Isolate* isolate, | 8602 static void IterateExternalArrayElements(Isolate* isolate, |
| 8328 Handle<JSObject> receiver, | 8603 Handle<JSObject> receiver, |
| 8329 bool elements_are_ints, | 8604 bool elements_are_ints, |
| 8330 bool elements_are_guaranteed_smis, | 8605 bool elements_are_guaranteed_smis, |
| 8331 uint32_t range, | 8606 ArrayConcatVisitor* visitor) { |
| 8332 ArrayConcatVisitor* visitor) { | |
| 8333 Handle<ExternalArrayClass> array( | 8607 Handle<ExternalArrayClass> array( |
| 8334 ExternalArrayClass::cast(receiver->elements())); | 8608 ExternalArrayClass::cast(receiver->elements())); |
| 8335 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); | 8609 uint32_t len = static_cast<uint32_t>(array->length()); |
| 8336 | 8610 |
| 8337 if (visitor != NULL) { | 8611 ASSERT(visitor != NULL); |
| 8338 if (elements_are_ints) { | 8612 if (elements_are_ints) { |
| 8339 if (elements_are_guaranteed_smis) { | 8613 if (elements_are_guaranteed_smis) { |
| 8340 for (uint32_t j = 0; j < len; j++) { | 8614 for (uint32_t j = 0; j < len; j++) { |
| 8341 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); | 8615 HandleScope loop_scope; |
| 8342 visitor->visit(j, e); | 8616 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); |
| 8343 } | 8617 visitor->visit(j, e); |
| 8344 } else { | |
| 8345 for (uint32_t j = 0; j < len; j++) { | |
| 8346 int64_t val = static_cast<int64_t>(array->get(j)); | |
| 8347 if (Smi::IsValid(static_cast<intptr_t>(val))) { | |
| 8348 Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); | |
| 8349 visitor->visit(j, e); | |
| 8350 } else { | |
| 8351 Handle<Object> e = | |
| 8352 isolate->factory()->NewNumber(static_cast<ElementType>(val)); | |
| 8353 visitor->visit(j, e); | |
| 8354 } | |
| 8355 } | |
| 8356 } | 8618 } |
| 8357 } else { | 8619 } else { |
| 8358 for (uint32_t j = 0; j < len; j++) { | 8620 for (uint32_t j = 0; j < len; j++) { |
| 8359 Handle<Object> e = isolate->factory()->NewNumber(array->get(j)); | 8621 HandleScope loop_scope; |
| 8360 visitor->visit(j, e); | 8622 int64_t val = static_cast<int64_t>(array->get(j)); |
| 8361 } | 8623 if (Smi::IsValid(static_cast<intptr_t>(val))) { |
| 8362 } | 8624 Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); |
| 8363 } | 8625 visitor->visit(j, e); |
| 8364 | 8626 } else { |
| 8365 return len; | 8627 Handle<Object> e = |
| 8366 } | 8628 isolate->factory()->NewNumber(static_cast<ElementType>(val)); |
| 8367 | 8629 visitor->visit(j, e); |
| 8368 /** | 8630 } |
| 8369 * A helper function that visits elements of a JSObject. Only elements | 8631 } |
| 8370 * whose index between 0 and range (exclusive) are visited. | 8632 } |
| 8371 * | 8633 } else { |
| 8372 * If the third parameter, visitor, is not NULL, the visitor is called | 8634 for (uint32_t j = 0; j < len; j++) { |
| 8373 * with parameters, 'visitor_index_offset + element index' and the element. | 8635 HandleScope loop_scope(isolate); |
| 8374 * | 8636 Handle<Object> e = isolate->factory()->NewNumber(array->get(j)); |
| 8375 * It returns the number of visisted elements. | 8637 visitor->visit(j, e); |
| 8376 */ | 8638 } |
| 8377 static uint32_t IterateElements(Isolate* isolate, | 8639 } |
| 8378 Handle<JSObject> receiver, | 8640 } |
| 8379 uint32_t range, | 8641 |
| 8380 ArrayConcatVisitor* visitor) { | 8642 |
| 8381 uint32_t num_of_elements = 0; | 8643 // Used for sorting indices in a List<uint32_t>. |
| 8382 | 8644 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { |
| 8383 switch (receiver->GetElementsKind()) { | 8645 uint32_t a = *ap; |
| 8646 uint32_t b = *bp; |
| 8647 return (a == b) ? 0 : (a < b) ? -1 : 1; |
| 8648 } |
| 8649 |
| 8650 |
| 8651 static void CollectElementIndices(Handle<JSObject> object, |
| 8652 uint32_t range, |
| 8653 List<uint32_t>* indices) { |
| 8654 JSObject::ElementsKind kind = object->GetElementsKind(); |
| 8655 switch (kind) { |
| 8384 case JSObject::FAST_ELEMENTS: { | 8656 case JSObject::FAST_ELEMENTS: { |
| 8385 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); | 8657 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
| 8386 uint32_t len = elements->length(); | 8658 uint32_t length = static_cast<uint32_t>(elements->length()); |
| 8387 if (range < len) { | 8659 if (range < length) length = range; |
| 8388 len = range; | 8660 for (uint32_t i = 0; i < length; i++) { |
| 8389 } | 8661 if (!elements->get(i)->IsTheHole()) { |
| 8390 | 8662 indices->Add(i); |
| 8391 for (uint32_t j = 0; j < len; j++) { | 8663 } |
| 8392 Handle<Object> e(elements->get(j), isolate); | 8664 } |
| 8393 if (!e->IsTheHole()) { | |
| 8394 num_of_elements++; | |
| 8395 if (visitor) { | |
| 8396 visitor->visit(j, e); | |
| 8397 } | |
| 8398 } | |
| 8399 } | |
| 8400 break; | |
| 8401 } | |
| 8402 case JSObject::PIXEL_ELEMENTS: { | |
| 8403 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements())); | |
| 8404 uint32_t len = pixels->length(); | |
| 8405 if (range < len) { | |
| 8406 len = range; | |
| 8407 } | |
| 8408 | |
| 8409 for (uint32_t j = 0; j < len; j++) { | |
| 8410 num_of_elements++; | |
| 8411 if (visitor != NULL) { | |
| 8412 Handle<Smi> e(Smi::FromInt(pixels->get(j))); | |
| 8413 visitor->visit(j, e); | |
| 8414 } | |
| 8415 } | |
| 8416 break; | |
| 8417 } | |
| 8418 case JSObject::EXTERNAL_BYTE_ELEMENTS: { | |
| 8419 num_of_elements = | |
| 8420 IterateExternalArrayElements<ExternalByteArray, int8_t>( | |
| 8421 isolate, receiver, true, true, range, visitor); | |
| 8422 break; | |
| 8423 } | |
| 8424 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | |
| 8425 num_of_elements = | |
| 8426 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( | |
| 8427 isolate, receiver, true, true, range, visitor); | |
| 8428 break; | |
| 8429 } | |
| 8430 case JSObject::EXTERNAL_SHORT_ELEMENTS: { | |
| 8431 num_of_elements = | |
| 8432 IterateExternalArrayElements<ExternalShortArray, int16_t>( | |
| 8433 isolate, receiver, true, true, range, visitor); | |
| 8434 break; | |
| 8435 } | |
| 8436 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { | |
| 8437 num_of_elements = | |
| 8438 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( | |
| 8439 isolate, receiver, true, true, range, visitor); | |
| 8440 break; | |
| 8441 } | |
| 8442 case JSObject::EXTERNAL_INT_ELEMENTS: { | |
| 8443 num_of_elements = | |
| 8444 IterateExternalArrayElements<ExternalIntArray, int32_t>( | |
| 8445 isolate, receiver, true, false, range, visitor); | |
| 8446 break; | |
| 8447 } | |
| 8448 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
| 8449 num_of_elements = | |
| 8450 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( | |
| 8451 isolate, receiver, true, false, range, visitor); | |
| 8452 break; | |
| 8453 } | |
| 8454 case JSObject::EXTERNAL_FLOAT_ELEMENTS: { | |
| 8455 num_of_elements = | |
| 8456 IterateExternalArrayElements<ExternalFloatArray, float>( | |
| 8457 isolate, receiver, false, false, range, visitor); | |
| 8458 break; | 8665 break; |
| 8459 } | 8666 } |
| 8460 case JSObject::DICTIONARY_ELEMENTS: { | 8667 case JSObject::DICTIONARY_ELEMENTS: { |
| 8461 Handle<NumberDictionary> dict(receiver->element_dictionary()); | 8668 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements())); |
| 8462 uint32_t capacity = dict->Capacity(); | 8669 uint32_t capacity = dict->Capacity(); |
| 8463 for (uint32_t j = 0; j < capacity; j++) { | 8670 for (uint32_t j = 0; j < capacity; j++) { |
| 8464 Handle<Object> k(dict->KeyAt(j), isolate); | 8671 HandleScope loop_scope; |
| 8672 Handle<Object> k(dict->KeyAt(j)); |
| 8465 if (dict->IsKey(*k)) { | 8673 if (dict->IsKey(*k)) { |
| 8466 ASSERT(k->IsNumber()); | 8674 ASSERT(k->IsNumber()); |
| 8467 uint32_t index = static_cast<uint32_t>(k->Number()); | 8675 uint32_t index = static_cast<uint32_t>(k->Number()); |
| 8468 if (index < range) { | 8676 if (index < range) { |
| 8469 num_of_elements++; | 8677 indices->Add(index); |
| 8470 if (visitor) { | |
| 8471 visitor->visit(index, Handle<Object>(dict->ValueAt(j), isolate)); | |
| 8472 } | |
| 8473 } | 8678 } |
| 8474 } | 8679 } |
| 8475 } | 8680 } |
| 8476 break; | 8681 break; |
| 8477 } | 8682 } |
| 8683 default: { |
| 8684 int dense_elements_length; |
| 8685 switch (kind) { |
| 8686 case JSObject::PIXEL_ELEMENTS: { |
| 8687 dense_elements_length = |
| 8688 PixelArray::cast(object->elements())->length(); |
| 8689 break; |
| 8690 } |
| 8691 case JSObject::EXTERNAL_BYTE_ELEMENTS: { |
| 8692 dense_elements_length = |
| 8693 ExternalByteArray::cast(object->elements())->length(); |
| 8694 break; |
| 8695 } |
| 8696 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { |
| 8697 dense_elements_length = |
| 8698 ExternalUnsignedByteArray::cast(object->elements())->length(); |
| 8699 break; |
| 8700 } |
| 8701 case JSObject::EXTERNAL_SHORT_ELEMENTS: { |
| 8702 dense_elements_length = |
| 8703 ExternalShortArray::cast(object->elements())->length(); |
| 8704 break; |
| 8705 } |
| 8706 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { |
| 8707 dense_elements_length = |
| 8708 ExternalUnsignedShortArray::cast(object->elements())->length(); |
| 8709 break; |
| 8710 } |
| 8711 case JSObject::EXTERNAL_INT_ELEMENTS: { |
| 8712 dense_elements_length = |
| 8713 ExternalIntArray::cast(object->elements())->length(); |
| 8714 break; |
| 8715 } |
| 8716 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { |
| 8717 dense_elements_length = |
| 8718 ExternalUnsignedIntArray::cast(object->elements())->length(); |
| 8719 break; |
| 8720 } |
| 8721 case JSObject::EXTERNAL_FLOAT_ELEMENTS: { |
| 8722 dense_elements_length = |
| 8723 ExternalFloatArray::cast(object->elements())->length(); |
| 8724 break; |
| 8725 } |
| 8726 default: |
| 8727 UNREACHABLE(); |
| 8728 dense_elements_length = 0; |
| 8729 break; |
| 8730 } |
| 8731 uint32_t length = static_cast<uint32_t>(dense_elements_length); |
| 8732 if (range <= length) { |
| 8733 length = range; |
| 8734 // We will add all indices, so we might as well clear it first |
| 8735 // and avoid duplicates. |
| 8736 indices->Clear(); |
| 8737 } |
| 8738 for (uint32_t i = 0; i < length; i++) { |
| 8739 indices->Add(i); |
| 8740 } |
| 8741 if (length == range) return; // All indices accounted for already. |
| 8742 break; |
| 8743 } |
| 8744 } |
| 8745 |
| 8746 Handle<Object> prototype(object->GetPrototype()); |
| 8747 if (prototype->IsJSObject()) { |
| 8748 // The prototype will usually have no inherited element indices, |
| 8749 // but we have to check. |
| 8750 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); |
| 8751 } |
| 8752 } |
| 8753 |
| 8754 |
| 8755 /** |
| 8756 * A helper function that visits elements of a JSArray in numerical |
| 8757 * order. |
| 8758 * |
| 8759 * The visitor argument called for each existing element in the array |
| 8760 * with the element index and the element's value. |
| 8761 * Afterwards it increments the base-index of the visitor by the array |
| 8762 * length. |
| 8763 */ |
| 8764 static void IterateElements(Isolate* isolate, |
| 8765 Handle<JSArray> receiver, |
| 8766 ArrayConcatVisitor* visitor) { |
| 8767 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); |
| 8768 switch (receiver->GetElementsKind()) { |
| 8769 case JSObject::FAST_ELEMENTS: { |
| 8770 // Run through the elements FixedArray and use HasElement and GetElement |
| 8771 // to check the prototype for missing elements. |
| 8772 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); |
| 8773 int fast_length = static_cast<int>(length); |
| 8774 ASSERT(fast_length <= elements->length()); |
| 8775 for (int j = 0; j < fast_length; j++) { |
| 8776 HandleScope loop_scope(isolate); |
| 8777 Handle<Object> element_value(elements->get(j), isolate); |
| 8778 if (!element_value->IsTheHole()) { |
| 8779 visitor->visit(j, element_value); |
| 8780 } else if (receiver->HasElement(j)) { |
| 8781 // Call GetElement on receiver, not its prototype, or getters won't |
| 8782 // have the correct receiver. |
| 8783 element_value = GetElement(receiver, j); |
| 8784 visitor->visit(j, element_value); |
| 8785 } |
| 8786 } |
| 8787 break; |
| 8788 } |
| 8789 case JSObject::DICTIONARY_ELEMENTS: { |
| 8790 Handle<NumberDictionary> dict(receiver->element_dictionary()); |
| 8791 List<uint32_t> indices(dict->Capacity() / 2); |
| 8792 // Collect all indices in the object and the prototypes less |
| 8793 // than length. This might introduce duplicates in the indices list. |
| 8794 CollectElementIndices(receiver, length, &indices); |
| 8795 indices.Sort(&compareUInt32); |
| 8796 int j = 0; |
| 8797 int n = indices.length(); |
| 8798 while (j < n) { |
| 8799 HandleScope loop_scope; |
| 8800 uint32_t index = indices[j]; |
| 8801 Handle<Object> element = GetElement(receiver, index); |
| 8802 visitor->visit(index, element); |
| 8803 // Skip to next different index (i.e., omit duplicates). |
| 8804 do { |
| 8805 j++; |
| 8806 } while (j < n && indices[j] == index); |
| 8807 } |
| 8808 break; |
| 8809 } |
| 8810 case JSObject::PIXEL_ELEMENTS: { |
| 8811 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements())); |
| 8812 for (uint32_t j = 0; j < length; j++) { |
| 8813 Handle<Smi> e(Smi::FromInt(pixels->get(j))); |
| 8814 visitor->visit(j, e); |
| 8815 } |
| 8816 break; |
| 8817 } |
| 8818 case JSObject::EXTERNAL_BYTE_ELEMENTS: { |
| 8819 IterateExternalArrayElements<ExternalByteArray, int8_t>( |
| 8820 isolate, receiver, true, true, visitor); |
| 8821 break; |
| 8822 } |
| 8823 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { |
| 8824 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( |
| 8825 isolate, receiver, true, true, visitor); |
| 8826 break; |
| 8827 } |
| 8828 case JSObject::EXTERNAL_SHORT_ELEMENTS: { |
| 8829 IterateExternalArrayElements<ExternalShortArray, int16_t>( |
| 8830 isolate, receiver, true, true, visitor); |
| 8831 break; |
| 8832 } |
| 8833 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { |
| 8834 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( |
| 8835 isolate, receiver, true, true, visitor); |
| 8836 break; |
| 8837 } |
| 8838 case JSObject::EXTERNAL_INT_ELEMENTS: { |
| 8839 IterateExternalArrayElements<ExternalIntArray, int32_t>( |
| 8840 isolate, receiver, true, false, visitor); |
| 8841 break; |
| 8842 } |
| 8843 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { |
| 8844 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( |
| 8845 isolate, receiver, true, false, visitor); |
| 8846 break; |
| 8847 } |
| 8848 case JSObject::EXTERNAL_FLOAT_ELEMENTS: { |
| 8849 IterateExternalArrayElements<ExternalFloatArray, float>( |
| 8850 isolate, receiver, false, false, visitor); |
| 8851 break; |
| 8852 } |
| 8478 default: | 8853 default: |
| 8479 UNREACHABLE(); | 8854 UNREACHABLE(); |
| 8480 break; | 8855 break; |
| 8481 } | 8856 } |
| 8482 | 8857 visitor->increase_index_offset(length); |
| 8483 return num_of_elements; | |
| 8484 } | |
| 8485 | |
| 8486 | |
| 8487 /** | |
| 8488 * A helper function that visits elements of an Array object, and elements | |
| 8489 * on its prototypes. | |
| 8490 * | |
| 8491 * Elements on prototypes are visited first, and only elements whose indices | |
| 8492 * less than Array length are visited. | |
| 8493 * | |
| 8494 * If a ArrayConcatVisitor object is given, the visitor is called with | |
| 8495 * parameters, element's index + visitor_index_offset and the element. | |
| 8496 * | |
| 8497 * The returned number of elements is an upper bound on the actual number | |
| 8498 * of elements added. If the same element occurs in more than one object | |
| 8499 * in the array's prototype chain, it will be counted more than once, but | |
| 8500 * will only occur once in the result. | |
| 8501 */ | |
| 8502 static uint32_t IterateArrayAndPrototypeElements(Isolate* isolate, | |
| 8503 Handle<JSArray> array, | |
| 8504 ArrayConcatVisitor* visitor) { | |
| 8505 uint32_t range = static_cast<uint32_t>(array->length()->Number()); | |
| 8506 Handle<Object> obj = array; | |
| 8507 | |
| 8508 static const int kEstimatedPrototypes = 3; | |
| 8509 List< Handle<JSObject> > objects(kEstimatedPrototypes); | |
| 8510 | |
| 8511 // Visit prototype first. If an element on the prototype is shadowed by | |
| 8512 // the inheritor using the same index, the ArrayConcatVisitor visits | |
| 8513 // the prototype element before the shadowing element. | |
| 8514 // The visitor can simply overwrite the old value by new value using | |
| 8515 // the same index. This follows Array::concat semantics. | |
| 8516 while (!obj->IsNull()) { | |
| 8517 objects.Add(Handle<JSObject>::cast(obj)); | |
| 8518 obj = Handle<Object>(obj->GetPrototype(), isolate); | |
| 8519 } | |
| 8520 | |
| 8521 uint32_t nof_elements = 0; | |
| 8522 for (int i = objects.length() - 1; i >= 0; i--) { | |
| 8523 Handle<JSObject> obj = objects[i]; | |
| 8524 uint32_t encountered_elements = | |
| 8525 IterateElements(isolate, Handle<JSObject>::cast(obj), range, visitor); | |
| 8526 | |
| 8527 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) { | |
| 8528 nof_elements = JSObject::kMaxElementCount; | |
| 8529 } else { | |
| 8530 nof_elements += encountered_elements; | |
| 8531 } | |
| 8532 } | |
| 8533 | |
| 8534 return nof_elements; | |
| 8535 } | |
| 8536 | |
| 8537 | |
| 8538 /** | |
| 8539 * A helper function of Runtime_ArrayConcat. | |
| 8540 * | |
| 8541 * The first argument is an Array of arrays and objects. It is the | |
| 8542 * same as the arguments array of Array::concat JS function. | |
| 8543 * | |
| 8544 * If an argument is an Array object, the function visits array | |
| 8545 * elements. If an argument is not an Array object, the function | |
| 8546 * visits the object as if it is an one-element array. | |
| 8547 * | |
| 8548 * If the result array index overflows 32-bit unsigned integer, the rounded | |
| 8549 * non-negative number is used as new length. For example, if one | |
| 8550 * array length is 2^32 - 1, second array length is 1, the | |
| 8551 * concatenated array length is 0. | |
| 8552 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length | |
| 8553 * is one more than the last array index to get a value assigned). | |
| 8554 */ | |
| 8555 static uint32_t IterateArguments(Isolate* isolate, | |
| 8556 Handle<JSArray> arguments, | |
| 8557 ArrayConcatVisitor* visitor) { | |
| 8558 uint32_t visited_elements = 0; | |
| 8559 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); | |
| 8560 | |
| 8561 for (uint32_t i = 0; i < num_of_args; i++) { | |
| 8562 Object* element; | |
| 8563 MaybeObject* maybe_element = arguments->GetElement(i); | |
| 8564 // This if() is not expected to fail, but we have the check in the | |
| 8565 // interest of hardening the runtime calls. | |
| 8566 if (maybe_element->ToObject(&element)) { | |
| 8567 Handle<Object> obj(element, isolate); | |
| 8568 if (obj->IsJSArray()) { | |
| 8569 Handle<JSArray> array = Handle<JSArray>::cast(obj); | |
| 8570 uint32_t len = static_cast<uint32_t>(array->length()->Number()); | |
| 8571 uint32_t nof_elements = | |
| 8572 IterateArrayAndPrototypeElements(isolate, array, visitor); | |
| 8573 // Total elements of array and its prototype chain can be more than | |
| 8574 // the array length, but ArrayConcat can only concatenate at most | |
| 8575 // the array length number of elements. We use the length as an estimate | |
| 8576 // for the actual number of elements added. | |
| 8577 uint32_t added_elements = (nof_elements > len) ? len : nof_elements; | |
| 8578 if (JSArray::kMaxElementCount - visited_elements < added_elements) { | |
| 8579 visited_elements = JSArray::kMaxElementCount; | |
| 8580 } else { | |
| 8581 visited_elements += added_elements; | |
| 8582 } | |
| 8583 if (visitor) visitor->increase_index_offset(len); | |
| 8584 } else { | |
| 8585 if (visitor) { | |
| 8586 visitor->visit(0, obj); | |
| 8587 visitor->increase_index_offset(1); | |
| 8588 } | |
| 8589 if (visited_elements < JSArray::kMaxElementCount) { | |
| 8590 visited_elements++; | |
| 8591 } | |
| 8592 } | |
| 8593 } | |
| 8594 } | |
| 8595 return visited_elements; | |
| 8596 } | 8858 } |
| 8597 | 8859 |
| 8598 | 8860 |
| 8599 /** | 8861 /** |
| 8600 * Array::concat implementation. | 8862 * Array::concat implementation. |
| 8601 * See ECMAScript 262, 15.4.4.4. | 8863 * See ECMAScript 262, 15.4.4.4. |
| 8602 * TODO(lrn): Fix non-compliance for very large concatenations and update to | 8864 * TODO(581): Fix non-compliance for very large concatenations and update to |
| 8603 * following the ECMAScript 5 specification. | 8865 * following the ECMAScript 5 specification. |
| 8604 */ | 8866 */ |
| 8605 static MaybeObject* Runtime_ArrayConcat(RUNTIME_CALLING_CONVENTION) { | 8867 static MaybeObject* Runtime_ArrayConcat(RUNTIME_CALLING_CONVENTION) { |
| 8606 RUNTIME_GET_ISOLATE; | 8868 RUNTIME_GET_ISOLATE; |
| 8607 ASSERT(args.length() == 1); | 8869 ASSERT(args.length() == 1); |
| 8608 HandleScope handle_scope(isolate); | 8870 HandleScope handle_scope(isolate); |
| 8609 | 8871 |
| 8610 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); | 8872 CONVERT_ARG_CHECKED(JSArray, arguments, 0); |
| 8611 Handle<JSArray> arguments(arg_arrays); | 8873 int argument_count = static_cast<int>(arguments->length()->Number()); |
| 8874 RUNTIME_ASSERT(arguments->HasFastElements()); |
| 8875 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); |
| 8612 | 8876 |
| 8613 // Pass 1: estimate the number of elements of the result | 8877 // Pass 1: estimate the length and number of elements of the result. |
| 8614 // (it could be more than real numbers if prototype has elements). | 8878 // The actual length can be larger if any of the arguments have getters |
| 8615 uint32_t result_length = 0; | 8879 // that mutate other arguments (but will otherwise be precise). |
| 8616 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); | 8880 // The number of elements is precise if there are no inherited elements. |
| 8617 | 8881 |
| 8618 { AssertNoAllocation nogc; | 8882 uint32_t estimate_result_length = 0; |
| 8619 for (uint32_t i = 0; i < num_of_args; i++) { | 8883 uint32_t estimate_nof_elements = 0; |
| 8620 Object* obj; | 8884 { |
| 8621 MaybeObject* maybe_object = arguments->GetElement(i); | 8885 for (int i = 0; i < argument_count; i++) { |
| 8622 // This if() is not expected to fail, but we have the check in the | 8886 HandleScope loop_scope; |
| 8623 // interest of hardening the runtime calls. | 8887 Handle<Object> obj(elements->get(i)); |
| 8624 if (maybe_object->ToObject(&obj)) { | 8888 uint32_t length_estimate; |
| 8625 uint32_t length_estimate; | 8889 uint32_t element_estimate; |
| 8626 if (obj->IsJSArray()) { | 8890 if (obj->IsJSArray()) { |
| 8627 length_estimate = | 8891 Handle<JSArray> array(Handle<JSArray>::cast(obj)); |
| 8628 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); | 8892 length_estimate = |
| 8629 } else { | 8893 static_cast<uint32_t>(array->length()->Number()); |
| 8630 length_estimate = 1; | 8894 element_estimate = |
| 8631 } | 8895 EstimateElementCount(array); |
| 8632 if (JSObject::kMaxElementCount - result_length < length_estimate) { | 8896 } else { |
| 8633 result_length = JSObject::kMaxElementCount; | 8897 length_estimate = 1; |
| 8634 break; | 8898 element_estimate = 1; |
| 8635 } | 8899 } |
| 8636 result_length += length_estimate; | 8900 // Avoid overflows by capping at kMaxElementCount. |
| 8901 if (JSObject::kMaxElementCount - estimate_result_length < |
| 8902 length_estimate) { |
| 8903 estimate_result_length = JSObject::kMaxElementCount; |
| 8904 } else { |
| 8905 estimate_result_length += length_estimate; |
| 8906 } |
| 8907 if (JSObject::kMaxElementCount - estimate_nof_elements < |
| 8908 element_estimate) { |
| 8909 estimate_nof_elements = JSObject::kMaxElementCount; |
| 8910 } else { |
| 8911 estimate_nof_elements += element_estimate; |
| 8637 } | 8912 } |
| 8638 } | 8913 } |
| 8639 } | 8914 } |
| 8640 | 8915 |
| 8641 // Allocate an empty array, will set length and content later. | |
| 8642 Handle<JSArray> result = isolate->factory()->NewJSArray(0); | |
| 8643 | |
| 8644 uint32_t estimate_nof_elements = IterateArguments(isolate, arguments, NULL); | |
| 8645 // If estimated number of elements is more than half of length, a | 8916 // If estimated number of elements is more than half of length, a |
| 8646 // fixed array (fast case) is more time and space-efficient than a | 8917 // fixed array (fast case) is more time and space-efficient than a |
| 8647 // dictionary. | 8918 // dictionary. |
| 8648 bool fast_case = (estimate_nof_elements * 2) >= result_length; | 8919 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; |
| 8649 | 8920 |
| 8650 Handle<FixedArray> storage; | 8921 Handle<FixedArray> storage; |
| 8651 if (fast_case) { | 8922 if (fast_case) { |
| 8652 // The backing storage array must have non-existing elements to | 8923 // The backing storage array must have non-existing elements to |
| 8653 // preserve holes across concat operations. | 8924 // preserve holes across concat operations. |
| 8654 storage = isolate->factory()->NewFixedArrayWithHoles(result_length); | 8925 storage = isolate->factory()->NewFixedArrayWithHoles( |
| 8655 Handle<Map> fast_map = | 8926 estimate_result_length); |
| 8656 isolate->factory()->GetFastElementsMap(Handle<Map>(result->map())); | |
| 8657 result->set_map(*fast_map); | |
| 8658 } else { | 8927 } else { |
| 8659 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | 8928 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate |
| 8660 uint32_t at_least_space_for = estimate_nof_elements + | 8929 uint32_t at_least_space_for = estimate_nof_elements + |
| 8661 (estimate_nof_elements >> 2); | 8930 (estimate_nof_elements >> 2); |
| 8662 storage = Handle<FixedArray>::cast( | 8931 storage = Handle<FixedArray>::cast( |
| 8663 isolate->factory()->NewNumberDictionary(at_least_space_for)); | 8932 isolate->factory()->NewNumberDictionary(at_least_space_for)); |
| 8664 Handle<Map> slow_map = | |
| 8665 isolate->factory()->GetSlowElementsMap(Handle<Map>(result->map())); | |
| 8666 result->set_map(*slow_map); | |
| 8667 } | 8933 } |
| 8668 | 8934 |
| 8669 Handle<Object> len = | 8935 ArrayConcatVisitor visitor(isolate, storage, fast_case); |
| 8670 isolate->factory()->NewNumber(static_cast<double>(result_length)); | |
| 8671 | 8936 |
| 8672 ArrayConcatVisitor visitor(storage, result_length, fast_case); | 8937 for (int i = 0; i < argument_count; i++) { |
| 8938 Handle<Object> obj(elements->get(i)); |
| 8939 if (obj->IsJSArray()) { |
| 8940 Handle<JSArray> array = Handle<JSArray>::cast(obj); |
| 8941 IterateElements(isolate, array, &visitor); |
| 8942 } else { |
| 8943 visitor.visit(0, obj); |
| 8944 visitor.increase_index_offset(1); |
| 8945 } |
| 8946 } |
| 8673 | 8947 |
| 8674 IterateArguments(isolate, arguments, &visitor); | 8948 return *visitor.ToArray(); |
| 8675 | |
| 8676 result->set_length(*len); | |
| 8677 // Please note the storage might have changed in the visitor. | |
| 8678 result->set_elements(*visitor.storage()); | |
| 8679 | |
| 8680 return *result; | |
| 8681 } | 8949 } |
| 8682 | 8950 |
| 8683 | 8951 |
| 8684 // This will not allocate (flatten the string), but it may run | 8952 // This will not allocate (flatten the string), but it may run |
| 8685 // very slowly for very deeply nested ConsStrings. For debugging use only. | 8953 // very slowly for very deeply nested ConsStrings. For debugging use only. |
| 8686 static MaybeObject* Runtime_GlobalPrint(RUNTIME_CALLING_CONVENTION) { | 8954 static MaybeObject* Runtime_GlobalPrint(RUNTIME_CALLING_CONVENTION) { |
| 8687 RUNTIME_GET_ISOLATE; | 8955 RUNTIME_GET_ISOLATE; |
| 8688 NoHandleAllocation ha; | 8956 NoHandleAllocation ha; |
| 8689 ASSERT(args.length() == 1); | 8957 ASSERT(args.length() == 1); |
| 8690 | 8958 |
| (...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9297 for (int i = 0; i < info.NumberOfLocals(); i++) { | 9565 for (int i = 0; i < info.NumberOfLocals(); i++) { |
| 9298 locals->set(i * 2, *info.LocalName(i)); | 9566 locals->set(i * 2, *info.LocalName(i)); |
| 9299 } | 9567 } |
| 9300 | 9568 |
| 9301 // Fill in the values of the locals. | 9569 // Fill in the values of the locals. |
| 9302 for (int i = 0; i < info.NumberOfLocals(); i++) { | 9570 for (int i = 0; i < info.NumberOfLocals(); i++) { |
| 9303 if (is_optimized_frame) { | 9571 if (is_optimized_frame) { |
| 9304 // If we are inspecting an optimized frame use undefined as the | 9572 // If we are inspecting an optimized frame use undefined as the |
| 9305 // value for all locals. | 9573 // value for all locals. |
| 9306 // | 9574 // |
| 9307 // TODO(3141533): We should be able to get the correct values | 9575 // TODO(1140): We should be able to get the correct values |
| 9308 // for locals in optimized frames. | 9576 // for locals in optimized frames. |
| 9309 locals->set(i * 2 + 1, isolate->heap()->undefined_value()); | 9577 locals->set(i * 2 + 1, isolate->heap()->undefined_value()); |
| 9310 } else if (i < info.number_of_stack_slots()) { | 9578 } else if (i < info.number_of_stack_slots()) { |
| 9311 // Get the value from the stack. | 9579 // Get the value from the stack. |
| 9312 locals->set(i * 2 + 1, it.frame()->GetExpression(i)); | 9580 locals->set(i * 2 + 1, it.frame()->GetExpression(i)); |
| 9313 } else { | 9581 } else { |
| 9314 // Traverse the context chain to the function context as all local | 9582 // Traverse the context chain to the function context as all local |
| 9315 // variables stored in the context will be on the function context. | 9583 // variables stored in the context will be on the function context. |
| 9316 Handle<String> name = info.LocalName(i); | 9584 Handle<String> name = info.LocalName(i); |
| 9317 while (!context->is_function_context()) { | 9585 while (!context->is_function_context()) { |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9464 isolate->factory()->ToObject(receiver, calling_frames_global_context); | 9732 isolate->factory()->ToObject(receiver, calling_frames_global_context); |
| 9465 } | 9733 } |
| 9466 details->set(kFrameDetailsReceiverIndex, *receiver); | 9734 details->set(kFrameDetailsReceiverIndex, *receiver); |
| 9467 | 9735 |
| 9468 ASSERT_EQ(details_size, details_index); | 9736 ASSERT_EQ(details_size, details_index); |
| 9469 return *isolate->factory()->NewJSArrayWithElements(details); | 9737 return *isolate->factory()->NewJSArrayWithElements(details); |
| 9470 } | 9738 } |
| 9471 | 9739 |
| 9472 | 9740 |
| 9473 // Copy all the context locals into an object used to materialize a scope. | 9741 // Copy all the context locals into an object used to materialize a scope. |
| 9474 static void CopyContextLocalsToScopeObject( | 9742 static bool CopyContextLocalsToScopeObject( |
| 9475 Isolate* isolate, | 9743 Isolate* isolate, |
| 9476 Handle<SerializedScopeInfo> serialized_scope_info, | 9744 Handle<SerializedScopeInfo> serialized_scope_info, |
| 9477 ScopeInfo<>& scope_info, | 9745 ScopeInfo<>& scope_info, |
| 9478 Handle<Context> context, | 9746 Handle<Context> context, |
| 9479 Handle<JSObject> scope_object) { | 9747 Handle<JSObject> scope_object) { |
| 9480 // Fill all context locals to the context extension. | 9748 // Fill all context locals to the context extension. |
| 9481 for (int i = Context::MIN_CONTEXT_SLOTS; | 9749 for (int i = Context::MIN_CONTEXT_SLOTS; |
| 9482 i < scope_info.number_of_context_slots(); | 9750 i < scope_info.number_of_context_slots(); |
| 9483 i++) { | 9751 i++) { |
| 9484 int context_index = serialized_scope_info->ContextSlotIndex( | 9752 int context_index = serialized_scope_info->ContextSlotIndex( |
| 9485 *scope_info.context_slot_name(i), NULL); | 9753 *scope_info.context_slot_name(i), NULL); |
| 9486 | 9754 |
| 9487 // Don't include the arguments shadow (.arguments) context variable. | 9755 // Don't include the arguments shadow (.arguments) context variable. |
| 9488 if (*scope_info.context_slot_name(i) != | 9756 if (*scope_info.context_slot_name(i) != |
| 9489 isolate->heap()->arguments_shadow_symbol()) { | 9757 isolate->heap()->arguments_shadow_symbol()) { |
| 9490 SetProperty(scope_object, | 9758 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9491 scope_info.context_slot_name(i), | 9759 isolate, |
| 9492 Handle<Object>(context->get(context_index), isolate), NONE); | 9760 SetProperty(scope_object, |
| 9761 scope_info.context_slot_name(i), |
| 9762 Handle<Object>(context->get(context_index), isolate), |
| 9763 NONE, |
| 9764 kNonStrictMode), |
| 9765 false); |
| 9493 } | 9766 } |
| 9494 } | 9767 } |
| 9768 |
| 9769 return true; |
| 9495 } | 9770 } |
| 9496 | 9771 |
| 9497 | 9772 |
| 9498 // Create a plain JSObject which materializes the local scope for the specified | 9773 // Create a plain JSObject which materializes the local scope for the specified |
| 9499 // frame. | 9774 // frame. |
| 9500 static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, | 9775 static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, |
| 9501 JavaScriptFrame* frame) { | 9776 JavaScriptFrame* frame) { |
| 9502 Handle<JSFunction> function(JSFunction::cast(frame->function())); | 9777 Handle<JSFunction> function(JSFunction::cast(frame->function())); |
| 9503 Handle<SharedFunctionInfo> shared(function->shared()); | 9778 Handle<SharedFunctionInfo> shared(function->shared()); |
| 9504 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info()); | 9779 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info()); |
| 9505 ScopeInfo<> scope_info(*serialized_scope_info); | 9780 ScopeInfo<> scope_info(*serialized_scope_info); |
| 9506 | 9781 |
| 9507 // Allocate and initialize a JSObject with all the arguments, stack locals | 9782 // Allocate and initialize a JSObject with all the arguments, stack locals |
| 9508 // heap locals and extension properties of the debugged function. | 9783 // heap locals and extension properties of the debugged function. |
| 9509 Handle<JSObject> local_scope = | 9784 Handle<JSObject> local_scope = |
| 9510 isolate->factory()->NewJSObject(isolate->object_function()); | 9785 isolate->factory()->NewJSObject(isolate->object_function()); |
| 9511 | 9786 |
| 9512 // First fill all parameters. | 9787 // First fill all parameters. |
| 9513 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { | 9788 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { |
| 9514 SetProperty(local_scope, | 9789 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9515 scope_info.parameter_name(i), | 9790 isolate, |
| 9516 Handle<Object>(frame->GetParameter(i), isolate), NONE); | 9791 SetProperty(local_scope, |
| 9792 scope_info.parameter_name(i), |
| 9793 Handle<Object>(frame->GetParameter(i), isolate), |
| 9794 NONE, |
| 9795 kNonStrictMode), |
| 9796 Handle<JSObject>()); |
| 9517 } | 9797 } |
| 9518 | 9798 |
| 9519 // Second fill all stack locals. | 9799 // Second fill all stack locals. |
| 9520 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { | 9800 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { |
| 9521 SetProperty(local_scope, | 9801 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9522 scope_info.stack_slot_name(i), | 9802 isolate, |
| 9523 Handle<Object>(frame->GetExpression(i), isolate), NONE); | 9803 SetProperty(local_scope, |
| 9804 scope_info.stack_slot_name(i), |
| 9805 Handle<Object>(frame->GetExpression(i), isolate), |
| 9806 NONE, |
| 9807 kNonStrictMode), |
| 9808 Handle<JSObject>()); |
| 9524 } | 9809 } |
| 9525 | 9810 |
| 9526 // Third fill all context locals. | 9811 // Third fill all context locals. |
| 9527 Handle<Context> frame_context(Context::cast(frame->context())); | 9812 Handle<Context> frame_context(Context::cast(frame->context())); |
| 9528 Handle<Context> function_context(frame_context->fcontext()); | 9813 Handle<Context> function_context(frame_context->fcontext()); |
| 9529 CopyContextLocalsToScopeObject(isolate, serialized_scope_info, scope_info, | 9814 if (!CopyContextLocalsToScopeObject(isolate, |
| 9530 function_context, local_scope); | 9815 serialized_scope_info, scope_info, |
| 9816 function_context, local_scope)) { |
| 9817 return Handle<JSObject>(); |
| 9818 } |
| 9531 | 9819 |
| 9532 // Finally copy any properties from the function context extension. This will | 9820 // Finally copy any properties from the function context extension. This will |
| 9533 // be variables introduced by eval. | 9821 // be variables introduced by eval. |
| 9534 if (function_context->closure() == *function) { | 9822 if (function_context->closure() == *function) { |
| 9535 if (function_context->has_extension() && | 9823 if (function_context->has_extension() && |
| 9536 !function_context->IsGlobalContext()) { | 9824 !function_context->IsGlobalContext()) { |
| 9537 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | 9825 Handle<JSObject> ext(JSObject::cast(function_context->extension())); |
| 9538 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); | 9826 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); |
| 9539 for (int i = 0; i < keys->length(); i++) { | 9827 for (int i = 0; i < keys->length(); i++) { |
| 9540 // Names of variables introduced by eval are strings. | 9828 // Names of variables introduced by eval are strings. |
| 9541 ASSERT(keys->get(i)->IsString()); | 9829 ASSERT(keys->get(i)->IsString()); |
| 9542 Handle<String> key(String::cast(keys->get(i))); | 9830 Handle<String> key(String::cast(keys->get(i))); |
| 9543 SetProperty(local_scope, key, GetProperty(ext, key), NONE); | 9831 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9832 isolate, |
| 9833 SetProperty(local_scope, |
| 9834 key, |
| 9835 GetProperty(ext, key), |
| 9836 NONE, |
| 9837 kNonStrictMode), |
| 9838 Handle<JSObject>()); |
| 9544 } | 9839 } |
| 9545 } | 9840 } |
| 9546 } | 9841 } |
| 9547 return local_scope; | 9842 return local_scope; |
| 9548 } | 9843 } |
| 9549 | 9844 |
| 9550 | 9845 |
| 9551 // Create a plain JSObject which materializes the closure content for the | 9846 // Create a plain JSObject which materializes the closure content for the |
| 9552 // context. | 9847 // context. |
| 9553 static Handle<JSObject> MaterializeClosure(Isolate* isolate, | 9848 static Handle<JSObject> MaterializeClosure(Isolate* isolate, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 9568 shared->scope_info()->ContextSlotIndex( | 9863 shared->scope_info()->ContextSlotIndex( |
| 9569 isolate->heap()->arguments_shadow_symbol(), NULL); | 9864 isolate->heap()->arguments_shadow_symbol(), NULL); |
| 9570 if (arguments_shadow_index >= 0) { | 9865 if (arguments_shadow_index >= 0) { |
| 9571 // In this case all the arguments are available in the arguments shadow | 9866 // In this case all the arguments are available in the arguments shadow |
| 9572 // object. | 9867 // object. |
| 9573 Handle<JSObject> arguments_shadow( | 9868 Handle<JSObject> arguments_shadow( |
| 9574 JSObject::cast(context->get(arguments_shadow_index))); | 9869 JSObject::cast(context->get(arguments_shadow_index))); |
| 9575 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { | 9870 for (int i = 0; i < scope_info.number_of_parameters(); ++i) { |
| 9576 // We don't expect exception-throwing getters on the arguments shadow. | 9871 // We don't expect exception-throwing getters on the arguments shadow. |
| 9577 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked(); | 9872 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked(); |
| 9578 SetProperty(closure_scope, | 9873 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9579 scope_info.parameter_name(i), | 9874 isolate, |
| 9580 Handle<Object>(element, isolate), | 9875 SetProperty(closure_scope, |
| 9581 NONE); | 9876 scope_info.parameter_name(i), |
| 9877 Handle<Object>(element, isolate), |
| 9878 NONE, |
| 9879 kNonStrictMode), |
| 9880 Handle<JSObject>()); |
| 9582 } | 9881 } |
| 9583 } | 9882 } |
| 9584 | 9883 |
| 9585 // Fill all context locals to the context extension. | 9884 // Fill all context locals to the context extension. |
| 9586 CopyContextLocalsToScopeObject(isolate, serialized_scope_info, scope_info, | 9885 if (!CopyContextLocalsToScopeObject(isolate, |
| 9587 context, closure_scope); | 9886 serialized_scope_info, scope_info, |
| 9887 context, closure_scope)) { |
| 9888 return Handle<JSObject>(); |
| 9889 } |
| 9588 | 9890 |
| 9589 // Finally copy any properties from the function context extension. This will | 9891 // Finally copy any properties from the function context extension. This will |
| 9590 // be variables introduced by eval. | 9892 // be variables introduced by eval. |
| 9591 if (context->has_extension()) { | 9893 if (context->has_extension()) { |
| 9592 Handle<JSObject> ext(JSObject::cast(context->extension())); | 9894 Handle<JSObject> ext(JSObject::cast(context->extension())); |
| 9593 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); | 9895 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); |
| 9594 for (int i = 0; i < keys->length(); i++) { | 9896 for (int i = 0; i < keys->length(); i++) { |
| 9595 // Names of variables introduced by eval are strings. | 9897 // Names of variables introduced by eval are strings. |
| 9596 ASSERT(keys->get(i)->IsString()); | 9898 ASSERT(keys->get(i)->IsString()); |
| 9597 Handle<String> key(String::cast(keys->get(i))); | 9899 Handle<String> key(String::cast(keys->get(i))); |
| 9598 SetProperty(closure_scope, key, GetProperty(ext, key), NONE); | 9900 RETURN_IF_EMPTY_HANDLE_VALUE( |
| 9901 isolate, |
| 9902 SetProperty(closure_scope, |
| 9903 key, |
| 9904 GetProperty(ext, key), |
| 9905 NONE, |
| 9906 kNonStrictMode), |
| 9907 Handle<JSObject>()); |
| 9599 } | 9908 } |
| 9600 } | 9909 } |
| 9601 | 9910 |
| 9602 return closure_scope; | 9911 return closure_scope; |
| 9603 } | 9912 } |
| 9604 | 9913 |
| 9605 | 9914 |
| 9606 // Iterate over the actual scopes visible from a stack frame. All scopes are | 9915 // Iterate over the actual scopes visible from a stack frame. All scopes are |
| 9607 // backed by an actual context except the local scope, which is inserted | 9916 // backed by an actual context except the local scope, which is inserted |
| 9608 // "artifically" in the context chain. | 9917 // "artifically" in the context chain. |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9879 return isolate->heap()->undefined_value(); | 10188 return isolate->heap()->undefined_value(); |
| 9880 } | 10189 } |
| 9881 | 10190 |
| 9882 // Calculate the size of the result. | 10191 // Calculate the size of the result. |
| 9883 int details_size = kScopeDetailsSize; | 10192 int details_size = kScopeDetailsSize; |
| 9884 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | 10193 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); |
| 9885 | 10194 |
| 9886 // Fill in scope details. | 10195 // Fill in scope details. |
| 9887 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); | 10196 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); |
| 9888 Handle<JSObject> scope_object = it.ScopeObject(); | 10197 Handle<JSObject> scope_object = it.ScopeObject(); |
| 10198 RETURN_IF_EMPTY_HANDLE(isolate, scope_object); |
| 9889 details->set(kScopeDetailsObjectIndex, *scope_object); | 10199 details->set(kScopeDetailsObjectIndex, *scope_object); |
| 9890 | 10200 |
| 9891 return *isolate->factory()->NewJSArrayWithElements(details); | 10201 return *isolate->factory()->NewJSArrayWithElements(details); |
| 9892 } | 10202 } |
| 9893 | 10203 |
| 9894 | 10204 |
| 9895 static MaybeObject* Runtime_DebugPrintScopes(RUNTIME_CALLING_CONVENTION) { | 10205 static MaybeObject* Runtime_DebugPrintScopes(RUNTIME_CALLING_CONVENTION) { |
| 9896 RUNTIME_GET_ISOLATE; | 10206 RUNTIME_GET_ISOLATE; |
| 9897 HandleScope scope(isolate); | 10207 HandleScope scope(isolate); |
| 9898 ASSERT(args.length() == 0); | 10208 ASSERT(args.length() == 0); |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10390 isolate->factory()->undefined_value()); | 10700 isolate->factory()->undefined_value()); |
| 10391 go_between->set_context(function->context()); | 10701 go_between->set_context(function->context()); |
| 10392 #ifdef DEBUG | 10702 #ifdef DEBUG |
| 10393 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info()); | 10703 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info()); |
| 10394 ASSERT(go_between_sinfo.number_of_parameters() == 0); | 10704 ASSERT(go_between_sinfo.number_of_parameters() == 0); |
| 10395 ASSERT(go_between_sinfo.number_of_context_slots() == 0); | 10705 ASSERT(go_between_sinfo.number_of_context_slots() == 0); |
| 10396 #endif | 10706 #endif |
| 10397 | 10707 |
| 10398 // Materialize the content of the local scope into a JSObject. | 10708 // Materialize the content of the local scope into a JSObject. |
| 10399 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame); | 10709 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame); |
| 10710 RETURN_IF_EMPTY_HANDLE(isolate, local_scope); |
| 10400 | 10711 |
| 10401 // Allocate a new context for the debug evaluation and set the extension | 10712 // Allocate a new context for the debug evaluation and set the extension |
| 10402 // object build. | 10713 // object build. |
| 10403 Handle<Context> context = | 10714 Handle<Context> context = |
| 10404 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, | 10715 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, |
| 10405 go_between); | 10716 go_between); |
| 10406 context->set_extension(*local_scope); | 10717 context->set_extension(*local_scope); |
| 10407 // Copy any with contexts present and chain them in front of this context. | 10718 // Copy any with contexts present and chain them in front of this context. |
| 10408 Handle<Context> frame_context(Context::cast(frame->context())); | 10719 Handle<Context> frame_context(Context::cast(frame->context())); |
| 10409 Handle<Context> function_context(frame_context->fcontext()); | 10720 Handle<Context> function_context(frame_context->fcontext()); |
| (...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11136 | 11447 |
| 11137 // Gets the current heap usage. | 11448 // Gets the current heap usage. |
| 11138 static MaybeObject* Runtime_GetHeapUsage(RUNTIME_CALLING_CONVENTION) { | 11449 static MaybeObject* Runtime_GetHeapUsage(RUNTIME_CALLING_CONVENTION) { |
| 11139 RUNTIME_GET_ISOLATE; | 11450 RUNTIME_GET_ISOLATE; |
| 11140 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); | 11451 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); |
| 11141 if (!Smi::IsValid(usage)) { | 11452 if (!Smi::IsValid(usage)) { |
| 11142 return *isolate->factory()->NewNumberFromInt(usage); | 11453 return *isolate->factory()->NewNumberFromInt(usage); |
| 11143 } | 11454 } |
| 11144 return Smi::FromInt(usage); | 11455 return Smi::FromInt(usage); |
| 11145 } | 11456 } |
| 11457 |
| 11458 |
| 11459 // Captures a live object list from the present heap. |
| 11460 static MaybeObject* Runtime_HasLOLEnabled(RUNTIME_CALLING_CONVENTION) { |
| 11461 RUNTIME_GET_ISOLATE; |
| 11462 #ifdef LIVE_OBJECT_LIST |
| 11463 return isolate->heap()->true_value(); |
| 11464 #else |
| 11465 return isolate->heap()->false_value(); |
| 11466 #endif |
| 11467 } |
| 11468 |
| 11469 |
| 11470 // Captures a live object list from the present heap. |
| 11471 static MaybeObject* Runtime_CaptureLOL(RUNTIME_CALLING_CONVENTION) { |
| 11472 RUNTIME_GET_ISOLATE; |
| 11473 #ifdef LIVE_OBJECT_LIST |
| 11474 return LiveObjectList::Capture(); |
| 11475 #else |
| 11476 return isolate->heap()->undefined_value(); |
| 11477 #endif |
| 11478 } |
| 11479 |
| 11480 |
| 11481 // Deletes the specified live object list. |
| 11482 static MaybeObject* Runtime_DeleteLOL(RUNTIME_CALLING_CONVENTION) { |
| 11483 RUNTIME_GET_ISOLATE; |
| 11484 #ifdef LIVE_OBJECT_LIST |
| 11485 CONVERT_SMI_CHECKED(id, args[0]); |
| 11486 bool success = LiveObjectList::Delete(id); |
| 11487 return success ? isolate->heap()->true_value() : |
| 11488 isolate->heap()->false_value(); |
| 11489 #else |
| 11490 return isolate->heap()->undefined_value(); |
| 11491 #endif |
| 11492 } |
| 11493 |
| 11494 |
| 11495 // Generates the response to a debugger request for a dump of the objects |
| 11496 // contained in the difference between the captured live object lists |
| 11497 // specified by id1 and id2. |
| 11498 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be |
| 11499 // dumped. |
| 11500 static MaybeObject* Runtime_DumpLOL(RUNTIME_CALLING_CONVENTION) { |
| 11501 RUNTIME_GET_ISOLATE; |
| 11502 #ifdef LIVE_OBJECT_LIST |
| 11503 HandleScope scope; |
| 11504 CONVERT_SMI_CHECKED(id1, args[0]); |
| 11505 CONVERT_SMI_CHECKED(id2, args[1]); |
| 11506 CONVERT_SMI_CHECKED(start, args[2]); |
| 11507 CONVERT_SMI_CHECKED(count, args[3]); |
| 11508 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4); |
| 11509 EnterDebugger enter_debugger; |
| 11510 return LiveObjectList::Dump(id1, id2, start, count, filter_obj); |
| 11511 #else |
| 11512 return isolate->heap()->undefined_value(); |
| 11513 #endif |
| 11514 } |
| 11515 |
| 11516 |
| 11517 // Gets the specified object as requested by the debugger. |
| 11518 // This is only used for obj ids shown in live object lists. |
| 11519 static MaybeObject* Runtime_GetLOLObj(RUNTIME_CALLING_CONVENTION) { |
| 11520 RUNTIME_GET_ISOLATE; |
| 11521 #ifdef LIVE_OBJECT_LIST |
| 11522 CONVERT_SMI_CHECKED(obj_id, args[0]); |
| 11523 Object* result = LiveObjectList::GetObj(obj_id); |
| 11524 return result; |
| 11525 #else |
| 11526 return isolate->heap()->undefined_value(); |
| 11527 #endif |
| 11528 } |
| 11529 |
| 11530 |
| 11531 // Gets the obj id for the specified address if valid. |
| 11532 // This is only used for obj ids shown in live object lists. |
| 11533 static MaybeObject* Runtime_GetLOLObjId(RUNTIME_CALLING_CONVENTION) { |
| 11534 RUNTIME_GET_ISOLATE; |
| 11535 #ifdef LIVE_OBJECT_LIST |
| 11536 HandleScope scope; |
| 11537 CONVERT_ARG_CHECKED(String, address, 0); |
| 11538 Object* result = LiveObjectList::GetObjId(address); |
| 11539 return result; |
| 11540 #else |
| 11541 return isolate->heap()->undefined_value(); |
| 11542 #endif |
| 11543 } |
| 11544 |
| 11545 |
| 11546 // Gets the retainers that references the specified object alive. |
| 11547 static MaybeObject* Runtime_GetLOLObjRetainers(RUNTIME_CALLING_CONVENTION) { |
| 11548 RUNTIME_GET_ISOLATE; |
| 11549 #ifdef LIVE_OBJECT_LIST |
| 11550 HandleScope scope; |
| 11551 CONVERT_SMI_CHECKED(obj_id, args[0]); |
| 11552 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject()); |
| 11553 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean()); |
| 11554 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi()); |
| 11555 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi()); |
| 11556 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5); |
| 11557 |
| 11558 Handle<JSObject> instance_filter; |
| 11559 if (args[1]->IsJSObject()) { |
| 11560 instance_filter = args.at<JSObject>(1); |
| 11561 } |
| 11562 bool verbose = false; |
| 11563 if (args[2]->IsBoolean()) { |
| 11564 verbose = args[2]->IsTrue(); |
| 11565 } |
| 11566 int start = 0; |
| 11567 if (args[3]->IsSmi()) { |
| 11568 start = Smi::cast(args[3])->value(); |
| 11569 } |
| 11570 int limit = Smi::kMaxValue; |
| 11571 if (args[4]->IsSmi()) { |
| 11572 limit = Smi::cast(args[4])->value(); |
| 11573 } |
| 11574 |
| 11575 return LiveObjectList::GetObjRetainers(obj_id, |
| 11576 instance_filter, |
| 11577 verbose, |
| 11578 start, |
| 11579 limit, |
| 11580 filter_obj); |
| 11581 #else |
| 11582 return isolate->heap()->undefined_value(); |
| 11583 #endif |
| 11584 } |
| 11585 |
| 11586 |
| 11587 // Gets the reference path between 2 objects. |
| 11588 static MaybeObject* Runtime_GetLOLPath(RUNTIME_CALLING_CONVENTION) { |
| 11589 RUNTIME_GET_ISOLATE; |
| 11590 #ifdef LIVE_OBJECT_LIST |
| 11591 HandleScope scope; |
| 11592 CONVERT_SMI_CHECKED(obj_id1, args[0]); |
| 11593 CONVERT_SMI_CHECKED(obj_id2, args[1]); |
| 11594 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject()); |
| 11595 |
| 11596 Handle<JSObject> instance_filter; |
| 11597 if (args[2]->IsJSObject()) { |
| 11598 instance_filter = args.at<JSObject>(2); |
| 11599 } |
| 11600 |
| 11601 Object* result = |
| 11602 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter); |
| 11603 return result; |
| 11604 #else |
| 11605 return isolate->heap()->undefined_value(); |
| 11606 #endif |
| 11607 } |
| 11608 |
| 11609 |
| 11610 // Generates the response to a debugger request for a list of all |
| 11611 // previously captured live object lists. |
| 11612 static MaybeObject* Runtime_InfoLOL(RUNTIME_CALLING_CONVENTION) { |
| 11613 RUNTIME_GET_ISOLATE; |
| 11614 #ifdef LIVE_OBJECT_LIST |
| 11615 CONVERT_SMI_CHECKED(start, args[0]); |
| 11616 CONVERT_SMI_CHECKED(count, args[1]); |
| 11617 return LiveObjectList::Info(start, count); |
| 11618 #else |
| 11619 return isolate->heap()->undefined_value(); |
| 11620 #endif |
| 11621 } |
| 11622 |
| 11623 |
| 11624 // Gets a dump of the specified object as requested by the debugger. |
| 11625 // This is only used for obj ids shown in live object lists. |
| 11626 static MaybeObject* Runtime_PrintLOLObj(RUNTIME_CALLING_CONVENTION) { |
| 11627 RUNTIME_GET_ISOLATE; |
| 11628 #ifdef LIVE_OBJECT_LIST |
| 11629 HandleScope scope; |
| 11630 CONVERT_SMI_CHECKED(obj_id, args[0]); |
| 11631 Object* result = LiveObjectList::PrintObj(obj_id); |
| 11632 return result; |
| 11633 #else |
| 11634 return isolate->heap()->undefined_value(); |
| 11635 #endif |
| 11636 } |
| 11637 |
| 11638 |
| 11639 // Resets and releases all previously captured live object lists. |
| 11640 static MaybeObject* Runtime_ResetLOL(RUNTIME_CALLING_CONVENTION) { |
| 11641 RUNTIME_GET_ISOLATE; |
| 11642 #ifdef LIVE_OBJECT_LIST |
| 11643 LiveObjectList::Reset(); |
| 11644 return isolate->heap()->undefined_value(); |
| 11645 #else |
| 11646 return isolate->heap()->undefined_value(); |
| 11647 #endif |
| 11648 } |
| 11649 |
| 11650 |
| 11651 // Generates the response to a debugger request for a summary of the types |
| 11652 // of objects in the difference between the captured live object lists |
| 11653 // specified by id1 and id2. |
| 11654 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be |
| 11655 // summarized. |
| 11656 static MaybeObject* Runtime_SummarizeLOL(RUNTIME_CALLING_CONVENTION) { |
| 11657 RUNTIME_GET_ISOLATE; |
| 11658 #ifdef LIVE_OBJECT_LIST |
| 11659 HandleScope scope; |
| 11660 CONVERT_SMI_CHECKED(id1, args[0]); |
| 11661 CONVERT_SMI_CHECKED(id2, args[1]); |
| 11662 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2); |
| 11663 |
| 11664 EnterDebugger enter_debugger; |
| 11665 return LiveObjectList::Summarize(id1, id2, filter_obj); |
| 11666 #else |
| 11667 return isolate->heap()->undefined_value(); |
| 11668 #endif |
| 11669 } |
| 11670 |
| 11146 #endif // ENABLE_DEBUGGER_SUPPORT | 11671 #endif // ENABLE_DEBUGGER_SUPPORT |
| 11147 | 11672 |
| 11148 | 11673 |
| 11149 #ifdef ENABLE_LOGGING_AND_PROFILING | 11674 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 11150 static MaybeObject* Runtime_ProfilerResume(RUNTIME_CALLING_CONVENTION) { | 11675 static MaybeObject* Runtime_ProfilerResume(RUNTIME_CALLING_CONVENTION) { |
| 11151 RUNTIME_GET_ISOLATE; | 11676 RUNTIME_GET_ISOLATE; |
| 11152 NoHandleAllocation ha; | 11677 NoHandleAllocation ha; |
| 11153 ASSERT(args.length() == 2); | 11678 ASSERT(args.length() == 2); |
| 11154 | 11679 |
| 11155 CONVERT_CHECKED(Smi, smi_modules, args[0]); | 11680 CONVERT_CHECKED(Smi, smi_modules, args[0]); |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11596 } else { | 12121 } else { |
| 11597 // Handle last resort GC and make sure to allow future allocations | 12122 // Handle last resort GC and make sure to allow future allocations |
| 11598 // to grow the heap without causing GCs (if possible). | 12123 // to grow the heap without causing GCs (if possible). |
| 11599 COUNTERS->gc_last_resort_from_js()->Increment(); | 12124 COUNTERS->gc_last_resort_from_js()->Increment(); |
| 11600 HEAP->CollectAllGarbage(false); | 12125 HEAP->CollectAllGarbage(false); |
| 11601 } | 12126 } |
| 11602 } | 12127 } |
| 11603 | 12128 |
| 11604 | 12129 |
| 11605 } } // namespace v8::internal | 12130 } } // namespace v8::internal |
| OLD | NEW |