| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #include "accessors.h" | 32 #include "accessors.h" |
| 33 #include "api.h" | 33 #include "api.h" |
| 34 #include "arguments.h" | 34 #include "arguments.h" |
| 35 #include "compiler.h" | 35 #include "compiler.h" |
| 36 #include "cpu.h" | 36 #include "cpu.h" |
| 37 #include "dateparser-inl.h" | 37 #include "dateparser-inl.h" |
| 38 #include "debug.h" | 38 #include "debug.h" |
| 39 #include "execution.h" | 39 #include "execution.h" |
| 40 #include "jsregexp.h" | 40 #include "jsregexp.h" |
| 41 #include "liveedit.h" |
| 41 #include "parser.h" | 42 #include "parser.h" |
| 42 #include "platform.h" | 43 #include "platform.h" |
| 43 #include "runtime.h" | 44 #include "runtime.h" |
| 44 #include "scopeinfo.h" | 45 #include "scopeinfo.h" |
| 45 #include "smart-pointer.h" | 46 #include "smart-pointer.h" |
| 46 #include "stub-cache.h" | 47 #include "stub-cache.h" |
| 47 #include "v8threads.h" | 48 #include "v8threads.h" |
| 48 | 49 |
| 49 namespace v8 { | 50 namespace v8 { |
| 50 namespace internal { | 51 namespace internal { |
| (...skipping 1172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1223 Counters::regexp_entry_runtime.Increment(); | 1224 Counters::regexp_entry_runtime.Increment(); |
| 1224 Handle<Object> result = RegExpImpl::Exec(regexp, | 1225 Handle<Object> result = RegExpImpl::Exec(regexp, |
| 1225 subject, | 1226 subject, |
| 1226 index, | 1227 index, |
| 1227 last_match_info); | 1228 last_match_info); |
| 1228 if (result.is_null()) return Failure::Exception(); | 1229 if (result.is_null()) return Failure::Exception(); |
| 1229 return *result; | 1230 return *result; |
| 1230 } | 1231 } |
| 1231 | 1232 |
| 1232 | 1233 |
| 1234 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { |
| 1235 HandleScope scope; |
| 1236 ASSERT(args.length() == 1); |
| 1237 CONVERT_ARG_CHECKED(JSArray, prototype, 0); |
| 1238 // This is necessary to enable fast checks for absence of elements |
| 1239 // on Array.prototype and below. |
| 1240 prototype->set_elements(Heap::empty_fixed_array()); |
| 1241 return Smi::FromInt(0); |
| 1242 } |
| 1243 |
| 1244 |
| 1233 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { | 1245 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { |
| 1234 HandleScope scope; | 1246 HandleScope scope; |
| 1235 ASSERT(args.length() == 4); | 1247 ASSERT(args.length() == 4); |
| 1236 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 1248 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| 1237 int index = Smi::cast(args[1])->value(); | 1249 int index = Smi::cast(args[1])->value(); |
| 1238 Handle<String> pattern = args.at<String>(2); | 1250 Handle<String> pattern = args.at<String>(2); |
| 1239 Handle<String> flags = args.at<String>(3); | 1251 Handle<String> flags = args.at<String>(3); |
| 1240 | 1252 |
| 1241 // Get the RegExp function from the context in the literals array. | 1253 // Get the RegExp function from the context in the literals array. |
| 1242 // This is the RegExp function from the context in which the | 1254 // This is the RegExp function from the context in which the |
| (...skipping 1358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2601 } | 2613 } |
| 2602 | 2614 |
| 2603 int end = str1_length < str2_length ? str1_length : str2_length; | 2615 int end = str1_length < str2_length ? str1_length : str2_length; |
| 2604 | 2616 |
| 2605 // No need to flatten if we are going to find the answer on the first | 2617 // No need to flatten if we are going to find the answer on the first |
| 2606 // character. At this point we know there is at least one character | 2618 // character. At this point we know there is at least one character |
| 2607 // in each string, due to the trivial case handling above. | 2619 // in each string, due to the trivial case handling above. |
| 2608 int d = str1->Get(0) - str2->Get(0); | 2620 int d = str1->Get(0) - str2->Get(0); |
| 2609 if (d != 0) return Smi::FromInt(d); | 2621 if (d != 0) return Smi::FromInt(d); |
| 2610 | 2622 |
| 2611 str1->TryFlattenIfNotFlat(); | 2623 str1->TryFlatten(); |
| 2612 str2->TryFlattenIfNotFlat(); | 2624 str2->TryFlatten(); |
| 2613 | 2625 |
| 2614 static StringInputBuffer buf1; | 2626 static StringInputBuffer buf1; |
| 2615 static StringInputBuffer buf2; | 2627 static StringInputBuffer buf2; |
| 2616 | 2628 |
| 2617 buf1.Reset(str1); | 2629 buf1.Reset(str1); |
| 2618 buf2.Reset(str2); | 2630 buf2.Reset(str2); |
| 2619 | 2631 |
| 2620 for (int i = 0; i < end; i++) { | 2632 for (int i = 0; i < end; i++) { |
| 2621 uint16_t char1 = buf1.GetNext(); | 2633 uint16_t char1 = buf1.GetNext(); |
| 2622 uint16_t char2 = buf2.GetNext(); | 2634 uint16_t char2 = buf2.GetNext(); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2811 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); | 2823 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); |
| 2812 DeleteArray(str); | 2824 DeleteArray(str); |
| 2813 return res; | 2825 return res; |
| 2814 } | 2826 } |
| 2815 | 2827 |
| 2816 | 2828 |
| 2817 // Returns a single character string where first character equals | 2829 // Returns a single character string where first character equals |
| 2818 // string->Get(index). | 2830 // string->Get(index). |
| 2819 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 2831 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
| 2820 if (index < static_cast<uint32_t>(string->length())) { | 2832 if (index < static_cast<uint32_t>(string->length())) { |
| 2821 string->TryFlattenIfNotFlat(); | 2833 string->TryFlatten(); |
| 2822 return LookupSingleCharacterStringFromCode( | 2834 return LookupSingleCharacterStringFromCode( |
| 2823 string->Get(index)); | 2835 string->Get(index)); |
| 2824 } | 2836 } |
| 2825 return Execution::CharAt(string, index); | 2837 return Execution::CharAt(string, index); |
| 2826 } | 2838 } |
| 2827 | 2839 |
| 2828 | 2840 |
| 2829 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { | 2841 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { |
| 2830 // Handle [] indexing on Strings | 2842 // Handle [] indexing on Strings |
| 2831 if (object->IsString()) { | 2843 if (object->IsString()) { |
| 2832 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 2844 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
| 2833 if (!result->IsUndefined()) return *result; | 2845 if (!result->IsUndefined()) return *result; |
| 2834 } | 2846 } |
| 2835 | 2847 |
| 2836 // Handle [] indexing on String objects | 2848 // Handle [] indexing on String objects |
| 2837 if (object->IsStringObjectWithCharacterAt(index)) { | 2849 if (object->IsStringObjectWithCharacterAt(index)) { |
| 2838 Handle<JSValue> js_value = Handle<JSValue>::cast(object); | 2850 Handle<JSValue> js_value = Handle<JSValue>::cast(object); |
| 2839 Handle<Object> result = | 2851 Handle<Object> result = |
| 2840 GetCharAt(Handle<String>(String::cast(js_value->value())), index); | 2852 GetCharAt(Handle<String>(String::cast(js_value->value())), index); |
| 2841 if (!result->IsUndefined()) return *result; | 2853 if (!result->IsUndefined()) return *result; |
| 2842 } | 2854 } |
| 2843 | 2855 |
| 2844 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 2856 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 2845 Handle<Object> prototype = GetPrototype(object); | 2857 Handle<Object> prototype = GetPrototype(object); |
| 2846 return prototype->GetElement(index); | 2858 return prototype->GetElement(index); |
| 2847 } | 2859 } |
| 2848 | 2860 |
| 2861 return GetElement(object, index); |
| 2862 } |
| 2863 |
| 2864 |
| 2865 Object* Runtime::GetElement(Handle<Object> object, uint32_t index) { |
| 2849 return object->GetElement(index); | 2866 return object->GetElement(index); |
| 2850 } | 2867 } |
| 2851 | 2868 |
| 2852 | 2869 |
| 2853 Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) { | 2870 Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) { |
| 2854 HandleScope scope; | 2871 HandleScope scope; |
| 2855 | 2872 |
| 2856 if (object->IsUndefined() || object->IsNull()) { | 2873 if (object->IsUndefined() || object->IsNull()) { |
| 2857 Handle<Object> args[2] = { key, object }; | 2874 Handle<Object> args[2] = { key, object }; |
| 2858 Handle<Object> error = | 2875 Handle<Object> error = |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3065 if (result.is_null()) return Failure::Exception(); | 3082 if (result.is_null()) return Failure::Exception(); |
| 3066 return *value; | 3083 return *value; |
| 3067 } | 3084 } |
| 3068 | 3085 |
| 3069 if (key->IsString()) { | 3086 if (key->IsString()) { |
| 3070 Handle<Object> result; | 3087 Handle<Object> result; |
| 3071 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 3088 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
| 3072 result = SetElement(js_object, index, value); | 3089 result = SetElement(js_object, index, value); |
| 3073 } else { | 3090 } else { |
| 3074 Handle<String> key_string = Handle<String>::cast(key); | 3091 Handle<String> key_string = Handle<String>::cast(key); |
| 3075 key_string->TryFlattenIfNotFlat(); | 3092 key_string->TryFlatten(); |
| 3076 result = SetProperty(js_object, key_string, value, attr); | 3093 result = SetProperty(js_object, key_string, value, attr); |
| 3077 } | 3094 } |
| 3078 if (result.is_null()) return Failure::Exception(); | 3095 if (result.is_null()) return Failure::Exception(); |
| 3079 return *value; | 3096 return *value; |
| 3080 } | 3097 } |
| 3081 | 3098 |
| 3082 // Call-back into JavaScript to convert the key to a string. | 3099 // Call-back into JavaScript to convert the key to a string. |
| 3083 bool has_pending_exception = false; | 3100 bool has_pending_exception = false; |
| 3084 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 3101 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
| 3085 if (has_pending_exception) return Failure::Exception(); | 3102 if (has_pending_exception) return Failure::Exception(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3114 } | 3131 } |
| 3115 | 3132 |
| 3116 return js_object->SetElement(index, *value); | 3133 return js_object->SetElement(index, *value); |
| 3117 } | 3134 } |
| 3118 | 3135 |
| 3119 if (key->IsString()) { | 3136 if (key->IsString()) { |
| 3120 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 3137 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
| 3121 return js_object->SetElement(index, *value); | 3138 return js_object->SetElement(index, *value); |
| 3122 } else { | 3139 } else { |
| 3123 Handle<String> key_string = Handle<String>::cast(key); | 3140 Handle<String> key_string = Handle<String>::cast(key); |
| 3124 key_string->TryFlattenIfNotFlat(); | 3141 key_string->TryFlatten(); |
| 3125 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string, | 3142 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string, |
| 3126 *value, | 3143 *value, |
| 3127 attr); | 3144 attr); |
| 3128 } | 3145 } |
| 3129 } | 3146 } |
| 3130 | 3147 |
| 3131 // Call-back into JavaScript to convert the key to a string. | 3148 // Call-back into JavaScript to convert the key to a string. |
| 3132 bool has_pending_exception = false; | 3149 bool has_pending_exception = false; |
| 3133 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 3150 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
| 3134 if (has_pending_exception) return Failure::Exception(); | 3151 if (has_pending_exception) return Failure::Exception(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3166 if (key->IsString()) { | 3183 if (key->IsString()) { |
| 3167 key_string = Handle<String>::cast(key); | 3184 key_string = Handle<String>::cast(key); |
| 3168 } else { | 3185 } else { |
| 3169 // Call-back into JavaScript to convert the key to a string. | 3186 // Call-back into JavaScript to convert the key to a string. |
| 3170 bool has_pending_exception = false; | 3187 bool has_pending_exception = false; |
| 3171 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 3188 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
| 3172 if (has_pending_exception) return Failure::Exception(); | 3189 if (has_pending_exception) return Failure::Exception(); |
| 3173 key_string = Handle<String>::cast(converted); | 3190 key_string = Handle<String>::cast(converted); |
| 3174 } | 3191 } |
| 3175 | 3192 |
| 3176 key_string->TryFlattenIfNotFlat(); | 3193 key_string->TryFlatten(); |
| 3177 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); | 3194 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); |
| 3178 } | 3195 } |
| 3179 | 3196 |
| 3180 | 3197 |
| 3181 static Object* Runtime_SetProperty(Arguments args) { | 3198 static Object* Runtime_SetProperty(Arguments args) { |
| 3182 NoHandleAllocation ha; | 3199 NoHandleAllocation ha; |
| 3183 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); | 3200 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); |
| 3184 | 3201 |
| 3185 Handle<Object> object = args.at<Object>(0); | 3202 Handle<Object> object = args.at<Object>(0); |
| 3186 Handle<Object> key = args.at<Object>(1); | 3203 Handle<Object> key = args.at<Object>(1); |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3662 // host objects gives that it is okay to return "object" | 3679 // host objects gives that it is okay to return "object" |
| 3663 return Heap::object_symbol(); | 3680 return Heap::object_symbol(); |
| 3664 } | 3681 } |
| 3665 } | 3682 } |
| 3666 | 3683 |
| 3667 | 3684 |
| 3668 static Object* Runtime_StringToNumber(Arguments args) { | 3685 static Object* Runtime_StringToNumber(Arguments args) { |
| 3669 NoHandleAllocation ha; | 3686 NoHandleAllocation ha; |
| 3670 ASSERT(args.length() == 1); | 3687 ASSERT(args.length() == 1); |
| 3671 CONVERT_CHECKED(String, subject, args[0]); | 3688 CONVERT_CHECKED(String, subject, args[0]); |
| 3672 subject->TryFlattenIfNotFlat(); | 3689 subject->TryFlatten(); |
| 3673 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); | 3690 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); |
| 3674 } | 3691 } |
| 3675 | 3692 |
| 3676 | 3693 |
| 3677 static Object* Runtime_StringFromCharCodeArray(Arguments args) { | 3694 static Object* Runtime_StringFromCharCodeArray(Arguments args) { |
| 3678 NoHandleAllocation ha; | 3695 NoHandleAllocation ha; |
| 3679 ASSERT(args.length() == 1); | 3696 ASSERT(args.length() == 1); |
| 3680 | 3697 |
| 3681 CONVERT_CHECKED(JSArray, codes, args[0]); | 3698 CONVERT_CHECKED(JSArray, codes, args[0]); |
| 3682 int length = Smi::cast(codes->length())->value(); | 3699 int length = Smi::cast(codes->length())->value(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3744 return kNotEscaped[character] != 0; | 3761 return kNotEscaped[character] != 0; |
| 3745 } | 3762 } |
| 3746 | 3763 |
| 3747 | 3764 |
| 3748 static Object* Runtime_URIEscape(Arguments args) { | 3765 static Object* Runtime_URIEscape(Arguments args) { |
| 3749 const char hex_chars[] = "0123456789ABCDEF"; | 3766 const char hex_chars[] = "0123456789ABCDEF"; |
| 3750 NoHandleAllocation ha; | 3767 NoHandleAllocation ha; |
| 3751 ASSERT(args.length() == 1); | 3768 ASSERT(args.length() == 1); |
| 3752 CONVERT_CHECKED(String, source, args[0]); | 3769 CONVERT_CHECKED(String, source, args[0]); |
| 3753 | 3770 |
| 3754 source->TryFlattenIfNotFlat(); | 3771 source->TryFlatten(); |
| 3755 | 3772 |
| 3756 int escaped_length = 0; | 3773 int escaped_length = 0; |
| 3757 int length = source->length(); | 3774 int length = source->length(); |
| 3758 { | 3775 { |
| 3759 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 3776 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); |
| 3760 buffer->Reset(source); | 3777 buffer->Reset(source); |
| 3761 while (buffer->has_more()) { | 3778 while (buffer->has_more()) { |
| 3762 uint16_t character = buffer->GetNext(); | 3779 uint16_t character = buffer->GetNext(); |
| 3763 if (character >= 256) { | 3780 if (character >= 256) { |
| 3764 escaped_length += 6; | 3781 escaped_length += 6; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3857 return character; | 3874 return character; |
| 3858 } | 3875 } |
| 3859 } | 3876 } |
| 3860 | 3877 |
| 3861 | 3878 |
| 3862 static Object* Runtime_URIUnescape(Arguments args) { | 3879 static Object* Runtime_URIUnescape(Arguments args) { |
| 3863 NoHandleAllocation ha; | 3880 NoHandleAllocation ha; |
| 3864 ASSERT(args.length() == 1); | 3881 ASSERT(args.length() == 1); |
| 3865 CONVERT_CHECKED(String, source, args[0]); | 3882 CONVERT_CHECKED(String, source, args[0]); |
| 3866 | 3883 |
| 3867 source->TryFlattenIfNotFlat(); | 3884 source->TryFlatten(); |
| 3868 | 3885 |
| 3869 bool ascii = true; | 3886 bool ascii = true; |
| 3870 int length = source->length(); | 3887 int length = source->length(); |
| 3871 | 3888 |
| 3872 int unescaped_length = 0; | 3889 int unescaped_length = 0; |
| 3873 for (int i = 0; i < length; unescaped_length++) { | 3890 for (int i = 0; i < length; unescaped_length++) { |
| 3874 int step; | 3891 int step; |
| 3875 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { | 3892 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { |
| 3876 ascii = false; | 3893 ascii = false; |
| 3877 } | 3894 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3897 return destination; | 3914 return destination; |
| 3898 } | 3915 } |
| 3899 | 3916 |
| 3900 | 3917 |
| 3901 static Object* Runtime_StringParseInt(Arguments args) { | 3918 static Object* Runtime_StringParseInt(Arguments args) { |
| 3902 NoHandleAllocation ha; | 3919 NoHandleAllocation ha; |
| 3903 | 3920 |
| 3904 CONVERT_CHECKED(String, s, args[0]); | 3921 CONVERT_CHECKED(String, s, args[0]); |
| 3905 CONVERT_SMI_CHECKED(radix, args[1]); | 3922 CONVERT_SMI_CHECKED(radix, args[1]); |
| 3906 | 3923 |
| 3907 s->TryFlattenIfNotFlat(); | 3924 s->TryFlatten(); |
| 3908 | 3925 |
| 3909 int len = s->length(); | 3926 int len = s->length(); |
| 3910 int i; | 3927 int i; |
| 3911 | 3928 |
| 3912 // Skip leading white space. | 3929 // Skip leading white space. |
| 3913 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; | 3930 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; |
| 3914 if (i == len) return Heap::nan_value(); | 3931 if (i == len) return Heap::nan_value(); |
| 3915 | 3932 |
| 3916 // Compute the sign (default to +). | 3933 // Compute the sign (default to +). |
| 3917 int sign = 1; | 3934 int sign = 1; |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4061 } else { | 4078 } else { |
| 4062 // If we didn't actually change anything in doing the conversion | 4079 // If we didn't actually change anything in doing the conversion |
| 4063 // we simple return the result and let the converted string | 4080 // we simple return the result and let the converted string |
| 4064 // become garbage; there is no reason to keep two identical strings | 4081 // become garbage; there is no reason to keep two identical strings |
| 4065 // alive. | 4082 // alive. |
| 4066 return s; | 4083 return s; |
| 4067 } | 4084 } |
| 4068 } | 4085 } |
| 4069 | 4086 |
| 4070 | 4087 |
| 4071 template <class Converter> | 4088 static inline SeqAsciiString* TryGetSeqAsciiString(String* s) { |
| 4072 static Object* ConvertCase(Arguments args, | 4089 if (!s->IsFlat() || !s->IsAsciiRepresentation()) return NULL; |
| 4073 unibrow::Mapping<Converter, 128>* mapping) { | 4090 if (s->IsConsString()) { |
| 4091 ASSERT(ConsString::cast(s)->second()->length() == 0); |
| 4092 return SeqAsciiString::cast(ConsString::cast(s)->first()); |
| 4093 } |
| 4094 return SeqAsciiString::cast(s); |
| 4095 } |
| 4096 |
| 4097 |
| 4098 namespace { |
| 4099 |
| 4100 struct ToLowerTraits { |
| 4101 typedef unibrow::ToLowercase UnibrowConverter; |
| 4102 |
| 4103 static bool ConvertAscii(char* dst, char* src, int length) { |
| 4104 bool changed = false; |
| 4105 for (int i = 0; i < length; ++i) { |
| 4106 char c = src[i]; |
| 4107 if ('A' <= c && c <= 'Z') { |
| 4108 c += ('a' - 'A'); |
| 4109 changed = true; |
| 4110 } |
| 4111 dst[i] = c; |
| 4112 } |
| 4113 return changed; |
| 4114 } |
| 4115 }; |
| 4116 |
| 4117 |
| 4118 struct ToUpperTraits { |
| 4119 typedef unibrow::ToUppercase UnibrowConverter; |
| 4120 |
| 4121 static bool ConvertAscii(char* dst, char* src, int length) { |
| 4122 bool changed = false; |
| 4123 for (int i = 0; i < length; ++i) { |
| 4124 char c = src[i]; |
| 4125 if ('a' <= c && c <= 'z') { |
| 4126 c -= ('a' - 'A'); |
| 4127 changed = true; |
| 4128 } |
| 4129 dst[i] = c; |
| 4130 } |
| 4131 return changed; |
| 4132 } |
| 4133 }; |
| 4134 |
| 4135 } // namespace |
| 4136 |
| 4137 |
| 4138 template <typename ConvertTraits> |
| 4139 static Object* ConvertCase( |
| 4140 Arguments args, |
| 4141 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { |
| 4074 NoHandleAllocation ha; | 4142 NoHandleAllocation ha; |
| 4143 CONVERT_CHECKED(String, s, args[0]); |
| 4144 s->TryFlatten(); |
| 4075 | 4145 |
| 4076 CONVERT_CHECKED(String, s, args[0]); | 4146 const int length = s->length(); |
| 4077 s->TryFlattenIfNotFlat(); | 4147 // Assume that the string is not empty; we need this assumption later |
| 4148 if (length == 0) return s; |
| 4078 | 4149 |
| 4079 int input_string_length = s->length(); | 4150 // Simpler handling of ascii strings. |
| 4080 // Assume that the string is not empty; we need this assumption later | 4151 // |
| 4081 if (input_string_length == 0) return s; | 4152 // NOTE: This assumes that the upper/lower case of an ascii |
| 4082 int length = input_string_length; | 4153 // character is also ascii. This is currently the case, but it |
| 4154 // might break in the future if we implement more context and locale |
| 4155 // dependent upper/lower conversions. |
| 4156 SeqAsciiString* seq_ascii = TryGetSeqAsciiString(s); |
| 4157 if (seq_ascii != NULL) { |
| 4158 Object* o = Heap::AllocateRawAsciiString(length); |
| 4159 if (o->IsFailure()) return o; |
| 4160 SeqAsciiString* result = SeqAsciiString::cast(o); |
| 4161 bool has_changed_character = ConvertTraits::ConvertAscii( |
| 4162 result->GetChars(), seq_ascii->GetChars(), length); |
| 4163 return has_changed_character ? result : s; |
| 4164 } |
| 4083 | 4165 |
| 4084 Object* answer = ConvertCaseHelper(s, length, length, mapping); | 4166 Object* answer = ConvertCaseHelper(s, length, length, mapping); |
| 4085 if (answer->IsSmi()) { | 4167 if (answer->IsSmi()) { |
| 4086 // Retry with correct length. | 4168 // Retry with correct length. |
| 4087 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); | 4169 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); |
| 4088 } | 4170 } |
| 4089 return answer; // This may be a failure. | 4171 return answer; // This may be a failure. |
| 4090 } | 4172 } |
| 4091 | 4173 |
| 4092 | 4174 |
| 4093 static Object* Runtime_StringToLowerCase(Arguments args) { | 4175 static Object* Runtime_StringToLowerCase(Arguments args) { |
| 4094 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); | 4176 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping); |
| 4095 } | 4177 } |
| 4096 | 4178 |
| 4097 | 4179 |
| 4098 static Object* Runtime_StringToUpperCase(Arguments args) { | 4180 static Object* Runtime_StringToUpperCase(Arguments args) { |
| 4099 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); | 4181 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping); |
| 4100 } | 4182 } |
| 4101 | 4183 |
| 4184 |
| 4102 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { | 4185 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { |
| 4103 return unibrow::WhiteSpace::Is(c) || c == 0x200b; | 4186 return unibrow::WhiteSpace::Is(c) || c == 0x200b; |
| 4104 } | 4187 } |
| 4105 | 4188 |
| 4189 |
| 4106 static Object* Runtime_StringTrim(Arguments args) { | 4190 static Object* Runtime_StringTrim(Arguments args) { |
| 4107 NoHandleAllocation ha; | 4191 NoHandleAllocation ha; |
| 4108 ASSERT(args.length() == 3); | 4192 ASSERT(args.length() == 3); |
| 4109 | 4193 |
| 4110 CONVERT_CHECKED(String, s, args[0]); | 4194 CONVERT_CHECKED(String, s, args[0]); |
| 4111 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]); | 4195 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]); |
| 4112 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]); | 4196 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]); |
| 4113 | 4197 |
| 4114 s->TryFlattenIfNotFlat(); | 4198 s->TryFlatten(); |
| 4115 int length = s->length(); | 4199 int length = s->length(); |
| 4116 | 4200 |
| 4117 int left = 0; | 4201 int left = 0; |
| 4118 if (trimLeft) { | 4202 if (trimLeft) { |
| 4119 while (left < length && IsTrimWhiteSpace(s->Get(left))) { | 4203 while (left < length && IsTrimWhiteSpace(s->Get(left))) { |
| 4120 left++; | 4204 left++; |
| 4121 } | 4205 } |
| 4122 } | 4206 } |
| 4123 | 4207 |
| 4124 int right = length; | 4208 int right = length; |
| 4125 if (trimRight) { | 4209 if (trimRight) { |
| 4126 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { | 4210 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { |
| 4127 right--; | 4211 right--; |
| 4128 } | 4212 } |
| 4129 } | 4213 } |
| 4130 return s->SubString(left, right); | 4214 return s->SubString(left, right); |
| 4131 } | 4215 } |
| 4132 | 4216 |
| 4217 |
| 4218 // Copies ascii characters to the given fixed array looking up |
| 4219 // one-char strings in the cache. Gives up on the first char that is |
| 4220 // not in the cache and fills the remainder with smi zeros. Returns |
| 4221 // the length of the successfully copied prefix. |
| 4222 static int CopyCachedAsciiCharsToArray(const char* chars, |
| 4223 FixedArray* elements, |
| 4224 int length) { |
| 4225 AssertNoAllocation nogc; |
| 4226 FixedArray* ascii_cache = Heap::single_character_string_cache(); |
| 4227 Object* undefined = Heap::undefined_value(); |
| 4228 int i; |
| 4229 for (i = 0; i < length; ++i) { |
| 4230 Object* value = ascii_cache->get(chars[i]); |
| 4231 if (value == undefined) break; |
| 4232 ASSERT(!Heap::InNewSpace(value)); |
| 4233 elements->set(i, value, SKIP_WRITE_BARRIER); |
| 4234 } |
| 4235 if (i < length) { |
| 4236 ASSERT(Smi::FromInt(0) == 0); |
| 4237 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); |
| 4238 } |
| 4239 #ifdef DEBUG |
| 4240 for (int j = 0; j < length; ++j) { |
| 4241 Object* element = elements->get(j); |
| 4242 ASSERT(element == Smi::FromInt(0) || |
| 4243 (element->IsString() && String::cast(element)->LooksValid())); |
| 4244 } |
| 4245 #endif |
| 4246 return i; |
| 4247 } |
| 4248 |
| 4249 |
| 4250 // Converts a String to JSArray. |
| 4251 // For example, "foo" => ["f", "o", "o"]. |
| 4252 static Object* Runtime_StringToArray(Arguments args) { |
| 4253 HandleScope scope; |
| 4254 ASSERT(args.length() == 1); |
| 4255 CONVERT_ARG_CHECKED(String, s, 0); |
| 4256 |
| 4257 s->TryFlatten(); |
| 4258 const int length = s->length(); |
| 4259 |
| 4260 Handle<FixedArray> elements; |
| 4261 if (s->IsFlat() && s->IsAsciiRepresentation()) { |
| 4262 Object* obj = Heap::AllocateUninitializedFixedArray(length); |
| 4263 if (obj->IsFailure()) return obj; |
| 4264 elements = Handle<FixedArray>(FixedArray::cast(obj)); |
| 4265 |
| 4266 Vector<const char> chars = s->ToAsciiVector(); |
| 4267 // Note, this will initialize all elements (not only the prefix) |
| 4268 // to prevent GC from seeing partially initialized array. |
| 4269 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(), |
| 4270 *elements, |
| 4271 length); |
| 4272 |
| 4273 for (int i = num_copied_from_cache; i < length; ++i) { |
| 4274 elements->set(i, *LookupSingleCharacterStringFromCode(chars[i])); |
| 4275 } |
| 4276 } else { |
| 4277 elements = Factory::NewFixedArray(length); |
| 4278 for (int i = 0; i < length; ++i) { |
| 4279 elements->set(i, *LookupSingleCharacterStringFromCode(s->Get(i))); |
| 4280 } |
| 4281 } |
| 4282 |
| 4283 #ifdef DEBUG |
| 4284 for (int i = 0; i < length; ++i) { |
| 4285 ASSERT(String::cast(elements->get(i))->length() == 1); |
| 4286 } |
| 4287 #endif |
| 4288 |
| 4289 return *Factory::NewJSArrayWithElements(elements); |
| 4290 } |
| 4291 |
| 4292 |
| 4133 bool Runtime::IsUpperCaseChar(uint16_t ch) { | 4293 bool Runtime::IsUpperCaseChar(uint16_t ch) { |
| 4134 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; | 4294 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; |
| 4135 int char_length = to_upper_mapping.get(ch, 0, chars); | 4295 int char_length = to_upper_mapping.get(ch, 0, chars); |
| 4136 return char_length == 0; | 4296 return char_length == 0; |
| 4137 } | 4297 } |
| 4138 | 4298 |
| 4139 | 4299 |
| 4140 static Object* Runtime_NumberToString(Arguments args) { | 4300 static Object* Runtime_NumberToString(Arguments args) { |
| 4141 NoHandleAllocation ha; | 4301 NoHandleAllocation ha; |
| 4142 ASSERT(args.length() == 1); | 4302 ASSERT(args.length() == 1); |
| 4143 | 4303 |
| 4144 Object* number = args[0]; | 4304 Object* number = args[0]; |
| 4145 RUNTIME_ASSERT(number->IsNumber()); | 4305 RUNTIME_ASSERT(number->IsNumber()); |
| 4146 | 4306 |
| 4147 return Heap::NumberToString(number); | 4307 return Heap::NumberToString(number); |
| 4148 } | 4308 } |
| 4149 | 4309 |
| 4150 | 4310 |
| 4151 static Object* Runtime_NumberToInteger(Arguments args) { | 4311 static Object* Runtime_NumberToInteger(Arguments args) { |
| 4152 NoHandleAllocation ha; | 4312 NoHandleAllocation ha; |
| 4153 ASSERT(args.length() == 1); | 4313 ASSERT(args.length() == 1); |
| 4154 | 4314 |
| 4155 Object* obj = args[0]; | 4315 CONVERT_DOUBLE_CHECKED(number, args[0]); |
| 4156 if (obj->IsSmi()) return obj; | 4316 |
| 4157 CONVERT_DOUBLE_CHECKED(number, obj); | 4317 // We do not include 0 so that we don't have to treat +0 / -0 cases. |
| 4318 if (number > 0 && number <= Smi::kMaxValue) { |
| 4319 return Smi::FromInt(static_cast<int>(number)); |
| 4320 } |
| 4158 return Heap::NumberFromDouble(DoubleToInteger(number)); | 4321 return Heap::NumberFromDouble(DoubleToInteger(number)); |
| 4159 } | 4322 } |
| 4160 | 4323 |
| 4161 | 4324 |
| 4162 static Object* Runtime_NumberToJSUint32(Arguments args) { | 4325 static Object* Runtime_NumberToJSUint32(Arguments args) { |
| 4163 NoHandleAllocation ha; | 4326 NoHandleAllocation ha; |
| 4164 ASSERT(args.length() == 1); | 4327 ASSERT(args.length() == 1); |
| 4165 | 4328 |
| 4166 Object* obj = args[0]; | 4329 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); |
| 4167 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj; | |
| 4168 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj); | |
| 4169 return Heap::NumberFromUint32(number); | 4330 return Heap::NumberFromUint32(number); |
| 4170 } | 4331 } |
| 4171 | 4332 |
| 4172 | 4333 |
| 4173 static Object* Runtime_NumberToJSInt32(Arguments args) { | 4334 static Object* Runtime_NumberToJSInt32(Arguments args) { |
| 4174 NoHandleAllocation ha; | 4335 NoHandleAllocation ha; |
| 4175 ASSERT(args.length() == 1); | 4336 ASSERT(args.length() == 1); |
| 4176 | 4337 |
| 4177 Object* obj = args[0]; | 4338 CONVERT_DOUBLE_CHECKED(number, args[0]); |
| 4178 if (obj->IsSmi()) return obj; | 4339 |
| 4179 CONVERT_DOUBLE_CHECKED(number, obj); | 4340 // We do not include 0 so that we don't have to treat +0 / -0 cases. |
| 4341 if (number > 0 && number <= Smi::kMaxValue) { |
| 4342 return Smi::FromInt(static_cast<int>(number)); |
| 4343 } |
| 4180 return Heap::NumberFromInt32(DoubleToInt32(number)); | 4344 return Heap::NumberFromInt32(DoubleToInt32(number)); |
| 4181 } | 4345 } |
| 4182 | 4346 |
| 4183 | 4347 |
| 4184 // Converts a Number to a Smi, if possible. Returns NaN if the number is not | 4348 // Converts a Number to a Smi, if possible. Returns NaN if the number is not |
| 4185 // a small integer. | 4349 // a small integer. |
| 4186 static Object* Runtime_NumberToSmi(Arguments args) { | 4350 static Object* Runtime_NumberToSmi(Arguments args) { |
| 4187 NoHandleAllocation ha; | 4351 NoHandleAllocation ha; |
| 4188 ASSERT(args.length() == 1); | 4352 ASSERT(args.length() == 1); |
| 4189 | 4353 |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4586 if (diff != 0) return Smi::FromInt(diff); | 4750 if (diff != 0) return Smi::FromInt(diff); |
| 4587 } | 4751 } |
| 4588 | 4752 |
| 4589 // If one array is a suffix of the other array, the longest array is | 4753 // If one array is a suffix of the other array, the longest array is |
| 4590 // the representation of the largest of the Smis in the | 4754 // the representation of the largest of the Smis in the |
| 4591 // lexicographic ordering. | 4755 // lexicographic ordering. |
| 4592 return Smi::FromInt(x_index - y_index); | 4756 return Smi::FromInt(x_index - y_index); |
| 4593 } | 4757 } |
| 4594 | 4758 |
| 4595 | 4759 |
| 4760 static Object* StringInputBufferCompare(String* x, String* y) { |
| 4761 static StringInputBuffer bufx; |
| 4762 static StringInputBuffer bufy; |
| 4763 bufx.Reset(x); |
| 4764 bufy.Reset(y); |
| 4765 while (bufx.has_more() && bufy.has_more()) { |
| 4766 int d = bufx.GetNext() - bufy.GetNext(); |
| 4767 if (d < 0) return Smi::FromInt(LESS); |
| 4768 else if (d > 0) return Smi::FromInt(GREATER); |
| 4769 } |
| 4770 |
| 4771 // x is (non-trivial) prefix of y: |
| 4772 if (bufy.has_more()) return Smi::FromInt(LESS); |
| 4773 // y is prefix of x: |
| 4774 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); |
| 4775 } |
| 4776 |
| 4777 |
| 4778 static Object* FlatStringCompare(String* x, String* y) { |
| 4779 ASSERT(x->IsFlat()); |
| 4780 ASSERT(y->IsFlat()); |
| 4781 Object* equal_prefix_result = Smi::FromInt(EQUAL); |
| 4782 int prefix_length = x->length(); |
| 4783 if (y->length() < prefix_length) { |
| 4784 prefix_length = y->length(); |
| 4785 equal_prefix_result = Smi::FromInt(GREATER); |
| 4786 } else if (y->length() > prefix_length) { |
| 4787 equal_prefix_result = Smi::FromInt(LESS); |
| 4788 } |
| 4789 int r; |
| 4790 if (x->IsAsciiRepresentation()) { |
| 4791 Vector<const char> x_chars = x->ToAsciiVector(); |
| 4792 if (y->IsAsciiRepresentation()) { |
| 4793 Vector<const char> y_chars = y->ToAsciiVector(); |
| 4794 r = memcmp(x_chars.start(), y_chars.start(), prefix_length); |
| 4795 } else { |
| 4796 Vector<const uc16> y_chars = y->ToUC16Vector(); |
| 4797 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4798 } |
| 4799 } else { |
| 4800 Vector<const uc16> x_chars = x->ToUC16Vector(); |
| 4801 if (y->IsAsciiRepresentation()) { |
| 4802 Vector<const char> y_chars = y->ToAsciiVector(); |
| 4803 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4804 } else { |
| 4805 Vector<const uc16> y_chars = y->ToUC16Vector(); |
| 4806 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4807 } |
| 4808 } |
| 4809 Object* result; |
| 4810 if (r == 0) { |
| 4811 result = equal_prefix_result; |
| 4812 } else { |
| 4813 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); |
| 4814 } |
| 4815 ASSERT(result == StringInputBufferCompare(x, y)); |
| 4816 return result; |
| 4817 } |
| 4818 |
| 4819 |
| 4596 static Object* Runtime_StringCompare(Arguments args) { | 4820 static Object* Runtime_StringCompare(Arguments args) { |
| 4597 NoHandleAllocation ha; | 4821 NoHandleAllocation ha; |
| 4598 ASSERT(args.length() == 2); | 4822 ASSERT(args.length() == 2); |
| 4599 | 4823 |
| 4600 CONVERT_CHECKED(String, x, args[0]); | 4824 CONVERT_CHECKED(String, x, args[0]); |
| 4601 CONVERT_CHECKED(String, y, args[1]); | 4825 CONVERT_CHECKED(String, y, args[1]); |
| 4602 | 4826 |
| 4603 Counters::string_compare_runtime.Increment(); | 4827 Counters::string_compare_runtime.Increment(); |
| 4604 | 4828 |
| 4605 // A few fast case tests before we flatten. | 4829 // A few fast case tests before we flatten. |
| 4606 if (x == y) return Smi::FromInt(EQUAL); | 4830 if (x == y) return Smi::FromInt(EQUAL); |
| 4607 if (y->length() == 0) { | 4831 if (y->length() == 0) { |
| 4608 if (x->length() == 0) return Smi::FromInt(EQUAL); | 4832 if (x->length() == 0) return Smi::FromInt(EQUAL); |
| 4609 return Smi::FromInt(GREATER); | 4833 return Smi::FromInt(GREATER); |
| 4610 } else if (x->length() == 0) { | 4834 } else if (x->length() == 0) { |
| 4611 return Smi::FromInt(LESS); | 4835 return Smi::FromInt(LESS); |
| 4612 } | 4836 } |
| 4613 | 4837 |
| 4614 int d = x->Get(0) - y->Get(0); | 4838 int d = x->Get(0) - y->Get(0); |
| 4615 if (d < 0) return Smi::FromInt(LESS); | 4839 if (d < 0) return Smi::FromInt(LESS); |
| 4616 else if (d > 0) return Smi::FromInt(GREATER); | 4840 else if (d > 0) return Smi::FromInt(GREATER); |
| 4617 | 4841 |
| 4618 x->TryFlattenIfNotFlat(); | 4842 x->TryFlatten(); |
| 4619 y->TryFlattenIfNotFlat(); | 4843 y->TryFlatten(); |
| 4620 | 4844 |
| 4621 static StringInputBuffer bufx; | 4845 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) |
| 4622 static StringInputBuffer bufy; | 4846 : StringInputBufferCompare(x, y); |
| 4623 bufx.Reset(x); | |
| 4624 bufy.Reset(y); | |
| 4625 while (bufx.has_more() && bufy.has_more()) { | |
| 4626 int d = bufx.GetNext() - bufy.GetNext(); | |
| 4627 if (d < 0) return Smi::FromInt(LESS); | |
| 4628 else if (d > 0) return Smi::FromInt(GREATER); | |
| 4629 } | |
| 4630 | |
| 4631 // x is (non-trivial) prefix of y: | |
| 4632 if (bufy.has_more()) return Smi::FromInt(LESS); | |
| 4633 // y is prefix of x: | |
| 4634 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); | |
| 4635 } | 4847 } |
| 4636 | 4848 |
| 4637 | 4849 |
| 4638 static Object* Runtime_Math_abs(Arguments args) { | 4850 static Object* Runtime_Math_abs(Arguments args) { |
| 4639 NoHandleAllocation ha; | 4851 NoHandleAllocation ha; |
| 4640 ASSERT(args.length() == 1); | 4852 ASSERT(args.length() == 1); |
| 4641 Counters::math_abs.Increment(); | 4853 Counters::math_abs.Increment(); |
| 4642 | 4854 |
| 4643 CONVERT_DOUBLE_CHECKED(x, args[0]); | 4855 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 4644 return Heap::AllocateHeapNumber(fabs(x)); | 4856 return Heap::AllocateHeapNumber(fabs(x)); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4811 | 5023 |
| 4812 if (y == 0) { | 5024 if (y == 0) { |
| 4813 return Smi::FromInt(1); | 5025 return Smi::FromInt(1); |
| 4814 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { | 5026 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { |
| 4815 return Heap::nan_value(); | 5027 return Heap::nan_value(); |
| 4816 } else { | 5028 } else { |
| 4817 return Heap::AllocateHeapNumber(pow(x, y)); | 5029 return Heap::AllocateHeapNumber(pow(x, y)); |
| 4818 } | 5030 } |
| 4819 } | 5031 } |
| 4820 | 5032 |
| 5033 // Fast version of Math.pow if we know that y is not an integer and |
| 5034 // y is not -0.5 or 0.5. Used as slowcase from codegen. |
| 5035 static Object* Runtime_Math_pow_cfunction(Arguments args) { |
| 5036 NoHandleAllocation ha; |
| 5037 ASSERT(args.length() == 2); |
| 5038 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 5039 CONVERT_DOUBLE_CHECKED(y, args[1]); |
| 5040 if (y == 0) { |
| 5041 return Smi::FromInt(1); |
| 5042 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { |
| 5043 return Heap::nan_value(); |
| 5044 } else { |
| 5045 return Heap::AllocateHeapNumber(pow(x, y)); |
| 5046 } |
| 5047 } |
| 5048 |
| 4821 | 5049 |
| 4822 static Object* Runtime_Math_round(Arguments args) { | 5050 static Object* Runtime_Math_round(Arguments args) { |
| 4823 NoHandleAllocation ha; | 5051 NoHandleAllocation ha; |
| 4824 ASSERT(args.length() == 1); | 5052 ASSERT(args.length() == 1); |
| 4825 Counters::math_round.Increment(); | 5053 Counters::math_round.Increment(); |
| 4826 | 5054 |
| 4827 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5055 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 4828 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); | 5056 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); |
| 4829 double integer = ceil(x); | 5057 double integer = ceil(x); |
| 4830 if (integer - x > 0.5) { integer -= 1.0; } | 5058 if (integer - x > 0.5) { integer -= 1.0; } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4855 static Object* Runtime_Math_tan(Arguments args) { | 5083 static Object* Runtime_Math_tan(Arguments args) { |
| 4856 NoHandleAllocation ha; | 5084 NoHandleAllocation ha; |
| 4857 ASSERT(args.length() == 1); | 5085 ASSERT(args.length() == 1); |
| 4858 Counters::math_tan.Increment(); | 5086 Counters::math_tan.Increment(); |
| 4859 | 5087 |
| 4860 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5088 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 4861 return TranscendentalCache::Get(TranscendentalCache::TAN, x); | 5089 return TranscendentalCache::Get(TranscendentalCache::TAN, x); |
| 4862 } | 5090 } |
| 4863 | 5091 |
| 4864 | 5092 |
| 5093 static Object* Runtime_DateMakeDay(Arguments args) { |
| 5094 NoHandleAllocation ha; |
| 5095 ASSERT(args.length() == 3); |
| 5096 |
| 5097 CONVERT_SMI_CHECKED(year, args[0]); |
| 5098 CONVERT_SMI_CHECKED(month, args[1]); |
| 5099 CONVERT_SMI_CHECKED(date, args[2]); |
| 5100 |
| 5101 static const int day_from_month[] = {0, 31, 59, 90, 120, 151, |
| 5102 181, 212, 243, 273, 304, 334}; |
| 5103 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, |
| 5104 182, 213, 244, 274, 305, 335}; |
| 5105 |
| 5106 year += month / 12; |
| 5107 month %= 12; |
| 5108 if (month < 0) { |
| 5109 year--; |
| 5110 month += 12; |
| 5111 } |
| 5112 |
| 5113 ASSERT(month >= 0); |
| 5114 ASSERT(month < 12); |
| 5115 |
| 5116 // year_delta is an arbitrary number such that: |
| 5117 // a) year_delta = -1 (mod 400) |
| 5118 // b) year + year_delta > 0 for years in the range defined by |
| 5119 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of |
| 5120 // Jan 1 1970. This is required so that we don't run into integer |
| 5121 // division of negative numbers. |
| 5122 // c) there shouldn't be overflow for 32-bit integers in the following |
| 5123 // operations. |
| 5124 static const int year_delta = 399999; |
| 5125 static const int base_day = 365 * (1970 + year_delta) + |
| 5126 (1970 + year_delta) / 4 - |
| 5127 (1970 + year_delta) / 100 + |
| 5128 (1970 + year_delta) / 400; |
| 5129 |
| 5130 int year1 = year + year_delta; |
| 5131 int day_from_year = 365 * year1 + |
| 5132 year1 / 4 - |
| 5133 year1 / 100 + |
| 5134 year1 / 400 - |
| 5135 base_day; |
| 5136 |
| 5137 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { |
| 5138 return Smi::FromInt(day_from_year + day_from_month[month] + date - 1); |
| 5139 } |
| 5140 |
| 5141 return Smi::FromInt(day_from_year + day_from_month_leap[month] + date - 1); |
| 5142 } |
| 5143 |
| 5144 |
| 4865 static Object* Runtime_NewArgumentsFast(Arguments args) { | 5145 static Object* Runtime_NewArgumentsFast(Arguments args) { |
| 4866 NoHandleAllocation ha; | 5146 NoHandleAllocation ha; |
| 4867 ASSERT(args.length() == 3); | 5147 ASSERT(args.length() == 3); |
| 4868 | 5148 |
| 4869 JSFunction* callee = JSFunction::cast(args[0]); | 5149 JSFunction* callee = JSFunction::cast(args[0]); |
| 4870 Object** parameters = reinterpret_cast<Object**>(args[1]); | 5150 Object** parameters = reinterpret_cast<Object**>(args[1]); |
| 4871 const int length = Smi::cast(args[2])->value(); | 5151 const int length = Smi::cast(args[2])->value(); |
| 4872 | 5152 |
| 4873 Object* result = Heap::AllocateArgumentsObject(callee, length); | 5153 Object* result = Heap::AllocateArgumentsObject(callee, length); |
| 4874 if (result->IsFailure()) return result; | 5154 if (result->IsFailure()) return result; |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5456 // and print some interesting cpu debugging info. | 5736 // and print some interesting cpu debugging info. |
| 5457 JavaScriptFrameIterator it; | 5737 JavaScriptFrameIterator it; |
| 5458 JavaScriptFrame* frame = it.frame(); | 5738 JavaScriptFrame* frame = it.frame(); |
| 5459 PrintF("fp = %p, sp = %p, caller_sp = %p: ", | 5739 PrintF("fp = %p, sp = %p, caller_sp = %p: ", |
| 5460 frame->fp(), frame->sp(), frame->caller_sp()); | 5740 frame->fp(), frame->sp(), frame->caller_sp()); |
| 5461 } else { | 5741 } else { |
| 5462 PrintF("DebugPrint: "); | 5742 PrintF("DebugPrint: "); |
| 5463 } | 5743 } |
| 5464 args[0]->Print(); | 5744 args[0]->Print(); |
| 5465 if (args[0]->IsHeapObject()) { | 5745 if (args[0]->IsHeapObject()) { |
| 5746 PrintF("\n"); |
| 5466 HeapObject::cast(args[0])->map()->Print(); | 5747 HeapObject::cast(args[0])->map()->Print(); |
| 5467 } | 5748 } |
| 5468 #else | 5749 #else |
| 5469 // ShortPrint is available in release mode. Print is not. | 5750 // ShortPrint is available in release mode. Print is not. |
| 5470 args[0]->ShortPrint(); | 5751 args[0]->ShortPrint(); |
| 5471 #endif | 5752 #endif |
| 5472 PrintF("\n"); | 5753 PrintF("\n"); |
| 5473 Flush(); | 5754 Flush(); |
| 5474 | 5755 |
| 5475 return args[0]; // return TOS | 5756 return args[0]; // return TOS |
| (...skipping 2528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8004 | 8285 |
| 8005 | 8286 |
| 8006 static Object* Runtime_FunctionGetInferredName(Arguments args) { | 8287 static Object* Runtime_FunctionGetInferredName(Arguments args) { |
| 8007 NoHandleAllocation ha; | 8288 NoHandleAllocation ha; |
| 8008 ASSERT(args.length() == 1); | 8289 ASSERT(args.length() == 1); |
| 8009 | 8290 |
| 8010 CONVERT_CHECKED(JSFunction, f, args[0]); | 8291 CONVERT_CHECKED(JSFunction, f, args[0]); |
| 8011 return f->shared()->inferred_name(); | 8292 return f->shared()->inferred_name(); |
| 8012 } | 8293 } |
| 8013 | 8294 |
| 8295 |
| 8296 static int FindSharedFunctionInfosForScript(Script* script, |
| 8297 FixedArray* buffer) { |
| 8298 AssertNoAllocation no_allocations; |
| 8299 |
| 8300 int counter = 0; |
| 8301 int buffer_size = buffer->length(); |
| 8302 HeapIterator iterator; |
| 8303 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| 8304 ASSERT(obj != NULL); |
| 8305 if (!obj->IsSharedFunctionInfo()) { |
| 8306 continue; |
| 8307 } |
| 8308 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); |
| 8309 if (shared->script() != script) { |
| 8310 continue; |
| 8311 } |
| 8312 if (counter < buffer_size) { |
| 8313 buffer->set(counter, shared); |
| 8314 } |
| 8315 counter++; |
| 8316 } |
| 8317 return counter; |
| 8318 } |
| 8319 |
| 8320 // For a script finds all SharedFunctionInfo's in the heap that points |
| 8321 // to this script. Returns JSArray of SharedFunctionInfo wrapped |
| 8322 // in OpaqueReferences. |
| 8323 static Object* Runtime_LiveEditFindSharedFunctionInfosForScript( |
| 8324 Arguments args) { |
| 8325 ASSERT(args.length() == 1); |
| 8326 HandleScope scope; |
| 8327 CONVERT_CHECKED(JSValue, script_value, args[0]); |
| 8328 |
| 8329 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); |
| 8330 |
| 8331 const int kBufferSize = 32; |
| 8332 |
| 8333 Handle<FixedArray> array; |
| 8334 array = Factory::NewFixedArray(kBufferSize); |
| 8335 int number = FindSharedFunctionInfosForScript(*script, *array); |
| 8336 if (number > kBufferSize) { |
| 8337 array = Factory::NewFixedArray(number); |
| 8338 FindSharedFunctionInfosForScript(*script, *array); |
| 8339 } |
| 8340 |
| 8341 Handle<JSArray> result = Factory::NewJSArrayWithElements(array); |
| 8342 result->set_length(Smi::FromInt(number)); |
| 8343 |
| 8344 LiveEdit::WrapSharedFunctionInfos(result); |
| 8345 |
| 8346 return *result; |
| 8347 } |
| 8348 |
| 8349 // For a script calculates compilation information about all its functions. |
| 8350 // The script source is explicitly specified by the second argument. |
| 8351 // The source of the actual script is not used, however it is important that |
| 8352 // all generated code keeps references to this particular instance of script. |
| 8353 // Returns a JSArray of compilation infos. The array is ordered so that |
| 8354 // each function with all its descendant is always stored in a continues range |
| 8355 // with the function itself going first. The root function is a script function. |
| 8356 static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) { |
| 8357 ASSERT(args.length() == 2); |
| 8358 HandleScope scope; |
| 8359 CONVERT_CHECKED(JSValue, script, args[0]); |
| 8360 CONVERT_ARG_CHECKED(String, source, 1); |
| 8361 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); |
| 8362 |
| 8363 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); |
| 8364 |
| 8365 if (Top::has_pending_exception()) { |
| 8366 return Failure::Exception(); |
| 8367 } |
| 8368 |
| 8369 return result; |
| 8370 } |
| 8371 |
| 8372 // Changes the source of the script to a new_source and creates a new |
| 8373 // script representing the old version of the script source. |
| 8374 static Object* Runtime_LiveEditReplaceScript(Arguments args) { |
| 8375 ASSERT(args.length() == 3); |
| 8376 HandleScope scope; |
| 8377 CONVERT_CHECKED(JSValue, original_script_value, args[0]); |
| 8378 CONVERT_ARG_CHECKED(String, new_source, 1); |
| 8379 CONVERT_ARG_CHECKED(String, old_script_name, 2); |
| 8380 Handle<Script> original_script = |
| 8381 Handle<Script>(Script::cast(original_script_value->value())); |
| 8382 |
| 8383 Handle<String> original_source(String::cast(original_script->source())); |
| 8384 |
| 8385 original_script->set_source(*new_source); |
| 8386 Handle<Script> old_script = Factory::NewScript(original_source); |
| 8387 old_script->set_name(*old_script_name); |
| 8388 old_script->set_line_offset(original_script->line_offset()); |
| 8389 old_script->set_column_offset(original_script->column_offset()); |
| 8390 old_script->set_data(original_script->data()); |
| 8391 old_script->set_type(original_script->type()); |
| 8392 old_script->set_context_data(original_script->context_data()); |
| 8393 old_script->set_compilation_type(original_script->compilation_type()); |
| 8394 old_script->set_eval_from_shared(original_script->eval_from_shared()); |
| 8395 old_script->set_eval_from_instructions_offset( |
| 8396 original_script->eval_from_instructions_offset()); |
| 8397 |
| 8398 |
| 8399 Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING); |
| 8400 |
| 8401 return *(GetScriptWrapper(old_script)); |
| 8402 } |
| 8403 |
| 8404 // Replaces code of SharedFunctionInfo with a new one. |
| 8405 static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) { |
| 8406 ASSERT(args.length() == 2); |
| 8407 HandleScope scope; |
| 8408 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0); |
| 8409 CONVERT_ARG_CHECKED(JSArray, shared_info, 1); |
| 8410 |
| 8411 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); |
| 8412 |
| 8413 return Heap::undefined_value(); |
| 8414 } |
| 8415 |
| 8416 // Connects SharedFunctionInfo to another script. |
| 8417 static Object* Runtime_LiveEditRelinkFunctionToScript(Arguments args) { |
| 8418 ASSERT(args.length() == 2); |
| 8419 HandleScope scope; |
| 8420 CONVERT_ARG_CHECKED(JSArray, shared_info_array, 0); |
| 8421 CONVERT_ARG_CHECKED(JSValue, script_value, 1); |
| 8422 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); |
| 8423 |
| 8424 LiveEdit::RelinkFunctionToScript(shared_info_array, script); |
| 8425 |
| 8426 return Heap::undefined_value(); |
| 8427 } |
| 8428 |
| 8429 // Updates positions of a shared function info (first parameter) according |
| 8430 // to script source change. Text change is described in second parameter as |
| 8431 // array of groups of 3 numbers: |
| 8432 // (change_begin, change_end, change_end_new_position). |
| 8433 // Each group describes a change in text; groups are sorted by change_begin. |
| 8434 static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) { |
| 8435 ASSERT(args.length() == 2); |
| 8436 HandleScope scope; |
| 8437 CONVERT_ARG_CHECKED(JSArray, shared_array, 0); |
| 8438 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1); |
| 8439 |
| 8440 LiveEdit::PatchFunctionPositions(shared_array, position_change_array); |
| 8441 |
| 8442 return Heap::undefined_value(); |
| 8443 } |
| 8444 |
| 8445 |
| 8446 static LiveEdit::FunctionPatchabilityStatus FindFunctionCodeOnStacks( |
| 8447 Handle<SharedFunctionInfo> shared) { |
| 8448 // TODO(635): check all threads, not only the current one. |
| 8449 for (StackFrameIterator it; !it.done(); it.Advance()) { |
| 8450 StackFrame* frame = it.frame(); |
| 8451 if (frame->code() == shared->code()) { |
| 8452 return LiveEdit::FUNCTION_BLOCKED_ON_STACK; |
| 8453 } |
| 8454 } |
| 8455 return LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH; |
| 8456 } |
| 8457 |
| 8458 // For array of SharedFunctionInfo's (each wrapped in JSValue) |
| 8459 // checks that none of them have activations on stacks (of any thread). |
| 8460 // Returns array of the same length with corresponding results of |
| 8461 // LiveEdit::FunctionPatchabilityStatus type. |
| 8462 static Object* Runtime_LiveEditCheckStackActivations(Arguments args) { |
| 8463 ASSERT(args.length() == 1); |
| 8464 HandleScope scope; |
| 8465 CONVERT_ARG_CHECKED(JSArray, shared_array, 0); |
| 8466 |
| 8467 |
| 8468 int len = Smi::cast(shared_array->length())->value(); |
| 8469 Handle<JSArray> result = Factory::NewJSArray(len); |
| 8470 |
| 8471 for (int i = 0; i < len; i++) { |
| 8472 JSValue* wrapper = JSValue::cast(shared_array->GetElement(i)); |
| 8473 Handle<SharedFunctionInfo> shared( |
| 8474 SharedFunctionInfo::cast(wrapper->value())); |
| 8475 LiveEdit::FunctionPatchabilityStatus check_res = |
| 8476 FindFunctionCodeOnStacks(shared); |
| 8477 SetElement(result, i, Handle<Smi>(Smi::FromInt(check_res))); |
| 8478 } |
| 8479 |
| 8480 return *result; |
| 8481 } |
| 8482 |
| 8483 |
| 8014 #endif // ENABLE_DEBUGGER_SUPPORT | 8484 #endif // ENABLE_DEBUGGER_SUPPORT |
| 8015 | 8485 |
| 8016 #ifdef ENABLE_LOGGING_AND_PROFILING | 8486 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 8017 | 8487 |
| 8018 static Object* Runtime_ProfilerResume(Arguments args) { | 8488 static Object* Runtime_ProfilerResume(Arguments args) { |
| 8019 NoHandleAllocation ha; | 8489 NoHandleAllocation ha; |
| 8020 ASSERT(args.length() == 2); | 8490 ASSERT(args.length() == 2); |
| 8021 | 8491 |
| 8022 CONVERT_CHECKED(Smi, smi_modules, args[0]); | 8492 CONVERT_CHECKED(Smi, smi_modules, args[0]); |
| 8023 CONVERT_CHECKED(Smi, smi_tag, args[1]); | 8493 CONVERT_CHECKED(Smi, smi_tag, args[1]); |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8279 } else { | 8749 } else { |
| 8280 // Handle last resort GC and make sure to allow future allocations | 8750 // Handle last resort GC and make sure to allow future allocations |
| 8281 // to grow the heap without causing GCs (if possible). | 8751 // to grow the heap without causing GCs (if possible). |
| 8282 Counters::gc_last_resort_from_js.Increment(); | 8752 Counters::gc_last_resort_from_js.Increment(); |
| 8283 Heap::CollectAllGarbage(false); | 8753 Heap::CollectAllGarbage(false); |
| 8284 } | 8754 } |
| 8285 } | 8755 } |
| 8286 | 8756 |
| 8287 | 8757 |
| 8288 } } // namespace v8::internal | 8758 } } // namespace v8::internal |
| OLD | NEW |