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

Side by Side Diff: src/runtime.cc

Issue 6580038: [Isolates] Merge from bleeding_edge, revisions 5934-6100. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 new_proto_map->set_is_hidden_prototype(); 637 new_proto_map->set_is_hidden_prototype();
638 638
639 // Set the object's prototype to proto. 639 // Set the object's prototype to proto.
640 new_map->set_prototype(proto); 640 new_map->set_prototype(proto);
641 jsobject->set_map(new_map); 641 jsobject->set_map(new_map);
642 642
643 return isolate->heap()->undefined_value(); 643 return isolate->heap()->undefined_value();
644 } 644 }
645 645
646 646
647 // Sets the magic number that identifies a function as one of the special
648 // math functions that can be inlined.
649 static MaybeObject* Runtime_SetMathFunctionId(RUNTIME_CALLING_CONVENTION) {
650 RUNTIME_GET_ISOLATE;
651 NoHandleAllocation ha;
652 ASSERT(args.length() == 2);
653 CONVERT_CHECKED(JSFunction, function, args[0]);
654 CONVERT_CHECKED(Smi, id, args[1]);
655 RUNTIME_ASSERT(id->value() >= 0);
656 RUNTIME_ASSERT(id->value() < SharedFunctionInfo::max_math_id_number());
657
658 function->shared()->set_math_function_id(id->value());
659
660 return isolate->heap()->undefined_value();
661 }
662
663
664 static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) { 647 static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
665 RUNTIME_GET_ISOLATE; 648 RUNTIME_GET_ISOLATE;
666 NoHandleAllocation ha; 649 NoHandleAllocation ha;
667 ASSERT(args.length() == 0); 650 ASSERT(args.length() == 0);
668 JavaScriptFrameIterator it; 651 JavaScriptFrameIterator it;
669 return isolate->heap()->ToBoolean(it.frame()->IsConstructor()); 652 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
670 } 653 }
671 654
672 655
673 // Recursively traverses hidden prototypes if property is not found 656 // Recursively traverses hidden prototypes if property is not found
(...skipping 2994 matching lines...) Expand 10 before | Expand all | Expand 10 after
3668 3651
3669 3652
3670 static MaybeObject* Runtime_DefineOrRedefineAccessorProperty( 3653 static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(
3671 RUNTIME_CALLING_CONVENTION) { 3654 RUNTIME_CALLING_CONVENTION) {
3672 RUNTIME_GET_ISOLATE; 3655 RUNTIME_GET_ISOLATE;
3673 ASSERT(args.length() == 5); 3656 ASSERT(args.length() == 5);
3674 HandleScope scope(isolate); 3657 HandleScope scope(isolate);
3675 CONVERT_ARG_CHECKED(JSObject, obj, 0); 3658 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3676 CONVERT_CHECKED(String, name, args[1]); 3659 CONVERT_CHECKED(String, name, args[1]);
3677 CONVERT_CHECKED(Smi, flag_setter, args[2]); 3660 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3678 CONVERT_CHECKED(JSFunction, fun, args[3]); 3661 Object* fun = args[3];
3662 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
3679 CONVERT_CHECKED(Smi, flag_attr, args[4]); 3663 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3680 int unchecked = flag_attr->value(); 3664 int unchecked = flag_attr->value();
3681 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 3665 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3682 RUNTIME_ASSERT(!obj->IsNull()); 3666 RUNTIME_ASSERT(!obj->IsNull());
3683 LookupResult result; 3667 LookupResult result;
3684 obj->LocalLookupRealNamedProperty(name, &result); 3668 obj->LocalLookupRealNamedProperty(name, &result);
3685 3669
3686 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 3670 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3687 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION 3671 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3688 // delete it to avoid running into trouble in DefineAccessor, which 3672 // delete it to avoid running into trouble in DefineAccessor, which
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
3726 // Normalize the elements to enable attributes on the property. 3710 // Normalize the elements to enable attributes on the property.
3727 NormalizeElements(js_object); 3711 NormalizeElements(js_object);
3728 Handle<NumberDictionary> dictionary(js_object->element_dictionary()); 3712 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
3729 // Make sure that we never go back to fast case. 3713 // Make sure that we never go back to fast case.
3730 dictionary->set_requires_slow_elements(); 3714 dictionary->set_requires_slow_elements();
3731 PropertyDetails details = PropertyDetails(attr, NORMAL); 3715 PropertyDetails details = PropertyDetails(attr, NORMAL);
3732 NumberDictionarySet(dictionary, index, obj_value, details); 3716 NumberDictionarySet(dictionary, index, obj_value, details);
3733 } 3717 }
3734 3718
3735 LookupResult result; 3719 LookupResult result;
3736 js_object->LocalLookupRealNamedProperty(*name, &result); 3720 js_object->LookupRealNamedProperty(*name, &result);
3737 3721
3738 // Take special care when attributes are different and there is already 3722 // Take special care when attributes are different and there is already
3739 // a property. For simplicity we normalize the property which enables us 3723 // a property. For simplicity we normalize the property which enables us
3740 // to not worry about changing the instance_descriptor and creating a new 3724 // to not worry about changing the instance_descriptor and creating a new
3741 // map. The current version of SetObjectProperty does not handle attributes 3725 // map. The current version of SetObjectProperty does not handle attributes
3742 // correctly in the case where a property is a field and is reset with 3726 // correctly in the case where a property is a field and is reset with
3743 // new attributes. 3727 // new attributes.
3744 if (result.IsProperty() && attr != result.GetAttributes()) { 3728 if (result.IsProperty() &&
3729 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
3745 // New attributes - normalize to avoid writing to instance descriptor 3730 // New attributes - normalize to avoid writing to instance descriptor
3746 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); 3731 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
3747 // Use IgnoreAttributes version since a readonly property may be 3732 // Use IgnoreAttributes version since a readonly property may be
3748 // overridden and SetProperty does not allow this. 3733 // overridden and SetProperty does not allow this.
3749 return js_object->IgnoreAttributesAndSetLocalProperty(*name, 3734 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3750 *obj_value, 3735 *obj_value,
3751 attr); 3736 attr);
3752 } 3737 }
3753 3738
3754 return Runtime::SetObjectProperty(isolate, js_object, name, obj_value, attr); 3739 return Runtime::SetObjectProperty(isolate, js_object, name, obj_value, attr);
(...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after
4745 int step; 4730 int step;
4746 destination->Set(dest_position, Unescape(source, i, length, &step)); 4731 destination->Set(dest_position, Unescape(source, i, length, &step));
4747 i += step; 4732 i += step;
4748 } 4733 }
4749 return destination; 4734 return destination;
4750 } 4735 }
4751 4736
4752 4737
4753 static const unsigned int kQuoteTableLength = 128u; 4738 static const unsigned int kQuoteTableLength = 128u;
4754 4739
4755 static const char* const JsonQuotes[kQuoteTableLength] = { 4740 static const int kJsonQuotesCharactersPerEntry = 8;
4756 "\\u0000", "\\u0001", "\\u0002", "\\u0003", 4741 static const char* const JsonQuotes =
4757 "\\u0004", "\\u0005", "\\u0006", "\\u0007", 4742 "\\u0000 \\u0001 \\u0002 \\u0003 "
4758 "\\b", "\\t", "\\n", "\\u000b", 4743 "\\u0004 \\u0005 \\u0006 \\u0007 "
4759 "\\f", "\\r", "\\u000e", "\\u000f", 4744 "\\b \\t \\n \\u000b "
4760 "\\u0010", "\\u0011", "\\u0012", "\\u0013", 4745 "\\f \\r \\u000e \\u000f "
4761 "\\u0014", "\\u0015", "\\u0016", "\\u0017", 4746 "\\u0010 \\u0011 \\u0012 \\u0013 "
4762 "\\u0018", "\\u0019", "\\u001a", "\\u001b", 4747 "\\u0014 \\u0015 \\u0016 \\u0017 "
4763 "\\u001c", "\\u001d", "\\u001e", "\\u001f", 4748 "\\u0018 \\u0019 \\u001a \\u001b "
4764 NULL, NULL, "\\\"", NULL, 4749 "\\u001c \\u001d \\u001e \\u001f "
4765 NULL, NULL, NULL, NULL, 4750 " ! \\\" # "
4766 NULL, NULL, NULL, NULL, 4751 "$ % & ' "
4767 NULL, NULL, NULL, NULL, 4752 "( ) * + "
4768 NULL, NULL, NULL, NULL, 4753 ", - . / "
4769 NULL, NULL, NULL, NULL, 4754 "0 1 2 3 "
4770 NULL, NULL, NULL, NULL, 4755 "4 5 6 7 "
4771 NULL, NULL, NULL, NULL, 4756 "8 9 : ; "
4772 NULL, NULL, NULL, NULL, 4757 "< = > ? "
4773 NULL, NULL, NULL, NULL, 4758 "@ A B C "
4774 NULL, NULL, NULL, NULL, 4759 "D E F G "
4775 NULL, NULL, NULL, NULL, 4760 "H I J K "
4776 NULL, NULL, NULL, NULL, 4761 "L M N O "
4777 NULL, NULL, NULL, NULL, 4762 "P Q R S "
4778 NULL, NULL, NULL, NULL, 4763 "T U V W "
4779 "\\\\", NULL, NULL, NULL, 4764 "X Y Z [ "
4780 NULL, NULL, NULL, NULL, 4765 "\\\\ ] ^ _ "
4781 NULL, NULL, NULL, NULL, 4766 "` a b c "
4782 NULL, NULL, NULL, NULL, 4767 "d e f g "
4783 NULL, NULL, NULL, NULL, 4768 "h i j k "
4784 NULL, NULL, NULL, NULL, 4769 "l m n o "
4785 NULL, NULL, NULL, NULL, 4770 "p q r s "
4786 NULL, NULL, NULL, NULL, 4771 "t u v w "
4787 NULL, NULL, NULL, NULL, 4772 "x y z { "
4788 }; 4773 "| } ~ \177 ";
4789 4774
4790 4775
4776 // For a string that is less than 32k characters it should always be
4777 // possible to allocate it in new space.
4778 static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4779
4780
4781 // Doing JSON quoting cannot make the string more than this many times larger.
4782 static const int kJsonQuoteWorstCaseBlowup = 6;
4783
4784
4785 // Covers the entire ASCII range (all other characters are unchanged by JSON
4786 // quoting).
4791 static const byte JsonQuoteLengths[kQuoteTableLength] = { 4787 static const byte JsonQuoteLengths[kQuoteTableLength] = {
4792 6, 6, 6, 6, 6, 6, 6, 6, 4788 6, 6, 6, 6, 6, 6, 6, 6,
4793 2, 2, 2, 6, 2, 2, 6, 6, 4789 2, 2, 2, 6, 2, 2, 6, 6,
4794 6, 6, 6, 6, 6, 6, 6, 6, 4790 6, 6, 6, 6, 6, 6, 6, 6,
4795 6, 6, 6, 6, 6, 6, 6, 6, 4791 6, 6, 6, 6, 6, 6, 6, 6,
4796 1, 1, 2, 1, 1, 1, 1, 1, 4792 1, 1, 2, 1, 1, 1, 1, 1,
4797 1, 1, 1, 1, 1, 1, 1, 1, 4793 1, 1, 1, 1, 1, 1, 1, 1,
4798 1, 1, 1, 1, 1, 1, 1, 1, 4794 1, 1, 1, 1, 1, 1, 1, 1,
4799 1, 1, 1, 1, 1, 1, 1, 1, 4795 1, 1, 1, 1, 1, 1, 1, 1,
4800 1, 1, 1, 1, 1, 1, 1, 1, 4796 1, 1, 1, 1, 1, 1, 1, 1,
4801 1, 1, 1, 1, 1, 1, 1, 1, 4797 1, 1, 1, 1, 1, 1, 1, 1,
4802 1, 1, 1, 1, 1, 1, 1, 1, 4798 1, 1, 1, 1, 1, 1, 1, 1,
4803 1, 1, 1, 1, 2, 1, 1, 1, 4799 1, 1, 1, 1, 2, 1, 1, 1,
4804 1, 1, 1, 1, 1, 1, 1, 1, 4800 1, 1, 1, 1, 1, 1, 1, 1,
4805 1, 1, 1, 1, 1, 1, 1, 1, 4801 1, 1, 1, 1, 1, 1, 1, 1,
4806 1, 1, 1, 1, 1, 1, 1, 1, 4802 1, 1, 1, 1, 1, 1, 1, 1,
4807 1, 1, 1, 1, 1, 1, 1, 1, 4803 1, 1, 1, 1, 1, 1, 1, 1,
4808 }; 4804 };
4809 4805
4810 4806
4811 template <typename Char>
4812 Char* WriteString(Char* dst, const char* src_string) {
4813 char c;
4814 for (c = *src_string; c; c = *src_string) {
4815 *dst = c;
4816 dst++;
4817 src_string++;
4818 }
4819 return dst;
4820 }
4821
4822
4823 template <typename StringType> 4807 template <typename StringType>
4824 MaybeObject* AllocateRawString(int length); 4808 MaybeObject* AllocateRawString(int length);
4825 4809
4826 4810
4827 template <> 4811 template <>
4828 MaybeObject* AllocateRawString<SeqTwoByteString>(int length) { 4812 MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4829 return HEAP->AllocateRawTwoByteString(length); 4813 return HEAP->AllocateRawTwoByteString(length);
4830 } 4814 }
4831 4815
4832 4816
4833 template <> 4817 template <>
4834 MaybeObject* AllocateRawString<SeqAsciiString>(int length) { 4818 MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4835 return HEAP->AllocateRawAsciiString(length); 4819 return HEAP->AllocateRawAsciiString(length);
4836 } 4820 }
4837 4821
4838 4822
4839 template <typename Char, typename StringType> 4823 template <typename Char, typename StringType>
4824 static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
4825 int length = characters.length();
4826 const Char* read_cursor = characters.start();
4827 const Char* end = read_cursor + length;
4828 const int kSpaceForQuotes = 2;
4829 int quoted_length = kSpaceForQuotes;
4830 while (read_cursor < end) {
4831 Char c = *(read_cursor++);
4832 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4833 quoted_length++;
4834 } else {
4835 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
4836 }
4837 }
4838 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4839 Object* new_object;
4840 if (!new_alloc->ToObject(&new_object)) {
4841 return new_alloc;
4842 }
4843 StringType* new_string = StringType::cast(new_object);
4844
4845 Char* write_cursor = reinterpret_cast<Char*>(
4846 new_string->address() + SeqAsciiString::kHeaderSize);
4847 *(write_cursor++) = '"';
4848
4849 read_cursor = characters.start();
4850 while (read_cursor < end) {
4851 Char c = *(read_cursor++);
4852 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4853 *(write_cursor++) = c;
4854 } else {
4855 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4856 const char* replacement = JsonQuotes +
4857 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4858 for (int i = 0; i < len; i++) {
4859 *write_cursor++ = *replacement++;
4860 }
4861 }
4862 }
4863 *(write_cursor++) = '"';
4864 return new_string;
4865 }
4866
4867
4868 template <typename Char, typename StringType>
4840 static MaybeObject* QuoteJsonString(Vector<const Char> characters) { 4869 static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4841 int length = characters.length(); 4870 int length = characters.length();
4842 int quoted_length = 0; 4871 COUNTERS->quote_json_char_count()->Increment(length);
4843 for (int i = 0; i < length; i++) { 4872 const int kSpaceForQuotes = 2;
4844 unsigned int c = characters[i]; 4873 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4845 if (sizeof(Char) > 1u) { 4874 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
4846 quoted_length += (c >= kQuoteTableLength) ? 1 : JsonQuoteLengths[c]; 4875 return SlowQuoteJsonString<Char, StringType>(characters);
4847 } else {
4848 quoted_length += JsonQuoteLengths[c];
4849 }
4850 } 4876 }
4851 COUNTERS->quote_json_char_count()->Increment(length);
4852 4877
4853 // Add space for quotes. 4878 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4854 quoted_length += 2;
4855
4856 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4857 Object* new_object; 4879 Object* new_object;
4858 if (!new_alloc->ToObject(&new_object)) { 4880 if (!new_alloc->ToObject(&new_object)) {
4859 COUNTERS->quote_json_char_recount()->Increment(length);
4860 return new_alloc; 4881 return new_alloc;
4861 } 4882 }
4883 if (!HEAP->new_space()->Contains(new_object)) {
4884 // Even if our string is small enough to fit in new space we still have to
4885 // handle it being allocated in old space as may happen in the third
4886 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4887 // CEntryStub::GenerateCore.
4888 return SlowQuoteJsonString<Char, StringType>(characters);
4889 }
4862 StringType* new_string = StringType::cast(new_object); 4890 StringType* new_string = StringType::cast(new_object);
4863 4891 ASSERT(HEAP->new_space()->Contains(new_string));
4864 4892
4865 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 4893 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4866 Char* write_cursor = reinterpret_cast<Char*>( 4894 Char* write_cursor = reinterpret_cast<Char*>(
4867 new_string->address() + SeqAsciiString::kHeaderSize); 4895 new_string->address() + SeqAsciiString::kHeaderSize);
4868 *(write_cursor++) = '"'; 4896 *(write_cursor++) = '"';
4897
4869 const Char* read_cursor = characters.start(); 4898 const Char* read_cursor = characters.start();
4870 if (quoted_length == length + 2) { 4899 const Char* end = read_cursor + length;
4871 CopyChars(write_cursor, read_cursor, length); 4900 while (read_cursor < end) {
4872 write_cursor += length; 4901 Char c = *(read_cursor++);
4873 } else { 4902 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4874 const Char* end = read_cursor + length; 4903 *(write_cursor++) = c;
4875 while (read_cursor < end) { 4904 } else {
4876 Char c = *(read_cursor++); 4905 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4877 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { 4906 const char* replacement = JsonQuotes +
4878 *(write_cursor++) = c; 4907 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4879 } else { 4908 write_cursor[0] = replacement[0];
4880 const char* replacement = JsonQuotes[static_cast<unsigned>(c)]; 4909 if (len > 1) {
4881 if (!replacement) { 4910 write_cursor[1] = replacement[1];
4882 *(write_cursor++) = c; 4911 if (len > 2) {
4883 } else { 4912 ASSERT(len == 6);
4884 write_cursor = WriteString(write_cursor, replacement); 4913 write_cursor[2] = replacement[2];
4914 write_cursor[3] = replacement[3];
4915 write_cursor[4] = replacement[4];
4916 write_cursor[5] = replacement[5];
4885 } 4917 }
4886 } 4918 }
4919 write_cursor += len;
4887 } 4920 }
4888 } 4921 }
4889 *(write_cursor++) = '"'; 4922 *(write_cursor++) = '"';
4890 ASSERT_EQ( 4923
4891 static_cast<int64_t>( 4924 int final_length = static_cast<int>(
4892 SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char)), 4925 write_cursor - reinterpret_cast<Char*>(
4893 static_cast<int64_t>( 4926 new_string->address() + SeqAsciiString::kHeaderSize));
4894 reinterpret_cast<Address>(write_cursor) - new_string->address())); 4927 HEAP->new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4928 final_length);
4895 return new_string; 4929 return new_string;
4896 } 4930 }
4897 4931
4898 4932
4899 static MaybeObject* Runtime_QuoteJSONString(RUNTIME_CALLING_CONVENTION) { 4933 static MaybeObject* Runtime_QuoteJSONString(RUNTIME_CALLING_CONVENTION) {
4900 RUNTIME_GET_ISOLATE; 4934 RUNTIME_GET_ISOLATE;
4901 NoHandleAllocation ha; 4935 NoHandleAllocation ha;
4902 CONVERT_CHECKED(String, str, args[0]); 4936 CONVERT_CHECKED(String, str, args[0]);
4903 if (!str->IsFlat()) { 4937 if (!str->IsFlat()) {
4904 MaybeObject* try_flatten = str->TryFlatten(); 4938 MaybeObject* try_flatten = str->TryFlatten();
(...skipping 1344 matching lines...) Expand 10 before | Expand all | Expand 10 after
6249 RUNTIME_GET_ISOLATE; 6283 RUNTIME_GET_ISOLATE;
6250 NoHandleAllocation ha; 6284 NoHandleAllocation ha;
6251 ASSERT(args.length() == 1); 6285 ASSERT(args.length() == 1);
6252 isolate->counters()->math_log()->Increment(); 6286 isolate->counters()->math_log()->Increment();
6253 6287
6254 CONVERT_DOUBLE_CHECKED(x, args[0]); 6288 CONVERT_DOUBLE_CHECKED(x, args[0]);
6255 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); 6289 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
6256 } 6290 }
6257 6291
6258 6292
6259 // Helper function to compute x^y, where y is known to be an
6260 // integer. Uses binary decomposition to limit the number of
6261 // multiplications; see the discussion in "Hacker's Delight" by Henry
6262 // S. Warren, Jr., figure 11-6, page 213.
6263 static double powi(double x, int y) {
6264 ASSERT(y != kMinInt);
6265 unsigned n = (y < 0) ? -y : y;
6266 double m = x;
6267 double p = 1;
6268 while (true) {
6269 if ((n & 1) != 0) p *= m;
6270 n >>= 1;
6271 if (n == 0) {
6272 if (y < 0) {
6273 // Unfortunately, we have to be careful when p has reached
6274 // infinity in the computation, because sometimes the higher
6275 // internal precision in the pow() implementation would have
6276 // given us a finite p. This happens very rarely.
6277 double result = 1.0 / p;
6278 return (result == 0 && isinf(p))
6279 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
6280 : result;
6281 } else {
6282 return p;
6283 }
6284 }
6285 m *= m;
6286 }
6287 }
6288
6289
6290 static MaybeObject* Runtime_Math_pow(RUNTIME_CALLING_CONVENTION) { 6293 static MaybeObject* Runtime_Math_pow(RUNTIME_CALLING_CONVENTION) {
6291 RUNTIME_GET_ISOLATE; 6294 RUNTIME_GET_ISOLATE;
6292 NoHandleAllocation ha; 6295 NoHandleAllocation ha;
6293 ASSERT(args.length() == 2); 6296 ASSERT(args.length() == 2);
6294 isolate->counters()->math_pow()->Increment(); 6297 isolate->counters()->math_pow()->Increment();
6295 6298
6296 CONVERT_DOUBLE_CHECKED(x, args[0]); 6299 CONVERT_DOUBLE_CHECKED(x, args[0]);
6297 6300
6298 // If the second argument is a smi, it is much faster to call the 6301 // If the second argument is a smi, it is much faster to call the
6299 // custom powi() function than the generic pow(). 6302 // custom powi() function than the generic pow().
6300 if (args[1]->IsSmi()) { 6303 if (args[1]->IsSmi()) {
6301 int y = Smi::cast(args[1])->value(); 6304 int y = Smi::cast(args[1])->value();
6302 return isolate->heap()->NumberFromDouble(powi(x, y)); 6305 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
6303 } 6306 }
6304 6307
6305 CONVERT_DOUBLE_CHECKED(y, args[1]); 6308 CONVERT_DOUBLE_CHECKED(y, args[1]);
6306 6309 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
6307 if (!isinf(x)) {
6308 if (y == 0.5) {
6309 // It's not uncommon to use Math.pow(x, 0.5) to compute the
6310 // square root of a number. To speed up such computations, we
6311 // explictly check for this case and use the sqrt() function
6312 // which is faster than pow().
6313 return isolate->heap()->AllocateHeapNumber(sqrt(x));
6314 } else if (y == -0.5) {
6315 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
6316 return isolate->heap()->AllocateHeapNumber(1.0 / sqrt(x));
6317 }
6318 }
6319
6320 if (y == 0) {
6321 return Smi::FromInt(1);
6322 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
6323 return isolate->heap()->nan_value();
6324 } else {
6325 return isolate->heap()->AllocateHeapNumber(pow(x, y));
6326 }
6327 } 6310 }
6328 6311
6329 // Fast version of Math.pow if we know that y is not an integer and 6312 // Fast version of Math.pow if we know that y is not an integer and
6330 // y is not -0.5 or 0.5. Used as slowcase from codegen. 6313 // y is not -0.5 or 0.5. Used as slowcase from codegen.
6331 static MaybeObject* Runtime_Math_pow_cfunction(RUNTIME_CALLING_CONVENTION) { 6314 static MaybeObject* Runtime_Math_pow_cfunction(RUNTIME_CALLING_CONVENTION) {
6332 RUNTIME_GET_ISOLATE; 6315 RUNTIME_GET_ISOLATE;
6333 NoHandleAllocation ha; 6316 NoHandleAllocation ha;
6334 ASSERT(args.length() == 2); 6317 ASSERT(args.length() == 2);
6335 CONVERT_DOUBLE_CHECKED(x, args[0]); 6318 CONVERT_DOUBLE_CHECKED(x, args[0]);
6336 CONVERT_DOUBLE_CHECKED(y, args[1]); 6319 CONVERT_DOUBLE_CHECKED(y, args[1]);
6337 if (y == 0) { 6320 if (y == 0) {
6338 return Smi::FromInt(1); 6321 return Smi::FromInt(1);
6339 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { 6322 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
6340 return isolate->heap()->nan_value(); 6323 return isolate->heap()->nan_value();
6341 } else { 6324 } else {
6342 return isolate->heap()->AllocateHeapNumber(pow(x, y)); 6325 return isolate->heap()->AllocateHeapNumber(pow(x, y));
6343 } 6326 }
6344 } 6327 }
6345 6328
6346 6329
6347 static MaybeObject* Runtime_RoundNumber(RUNTIME_CALLING_CONVENTION) { 6330 static MaybeObject* Runtime_RoundNumber(RUNTIME_CALLING_CONVENTION) {
6348 RUNTIME_GET_ISOLATE; 6331 RUNTIME_GET_ISOLATE;
6349 NoHandleAllocation ha; 6332 NoHandleAllocation ha;
6350 ASSERT(args.length() == 1); 6333 ASSERT(args.length() == 1);
6351 isolate->counters()->math_round()->Increment(); 6334 isolate->counters()->math_round()->Increment();
6352 6335
(...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after
7187 function->PrintName(); 7170 function->PrintName();
7188 PrintF("]\n"); 7171 PrintF("]\n");
7189 } 7172 }
7190 7173
7191 // Try to compile the optimized code. A true return value from 7174 // Try to compile the optimized code. A true return value from
7192 // CompileOptimized means that compilation succeeded, not necessarily 7175 // CompileOptimized means that compilation succeeded, not necessarily
7193 // that optimization succeeded. 7176 // that optimization succeeded.
7194 if (CompileOptimized(function, ast_id) && function->IsOptimized()) { 7177 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7195 DeoptimizationInputData* data = DeoptimizationInputData::cast( 7178 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7196 function->code()->deoptimization_data()); 7179 function->code()->deoptimization_data());
7197 if (FLAG_trace_osr) { 7180 if (data->OsrPcOffset()->value() >= 0) {
7198 PrintF("[on-stack replacement offset %d in optimized code]\n", 7181 if (FLAG_trace_osr) {
7182 PrintF("[on-stack replacement offset %d in optimized code]\n",
7199 data->OsrPcOffset()->value()); 7183 data->OsrPcOffset()->value());
7184 }
7185 ASSERT(data->OsrAstId()->value() == ast_id);
7186 } else {
7187 // We may never generate the desired OSR entry if we emit an
7188 // early deoptimize.
7189 succeeded = false;
7200 } 7190 }
7201 ASSERT(data->OsrAstId()->value() == ast_id);
7202 ASSERT(data->OsrPcOffset()->value() >= 0);
7203 } else { 7191 } else {
7204 succeeded = false; 7192 succeeded = false;
7205 } 7193 }
7206 } 7194 }
7207 7195
7208 // Revert to the original stack checks in the original unoptimized code. 7196 // Revert to the original stack checks in the original unoptimized code.
7209 if (FLAG_trace_osr) { 7197 if (FLAG_trace_osr) {
7210 PrintF("[restoring original stack checks in "); 7198 PrintF("[restoring original stack checks in ");
7211 function->PrintName(); 7199 function->PrintName();
7212 PrintF("]\n"); 7200 PrintF("]\n");
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
7526 // The property was not found. It needs to be stored in the global context. 7514 // The property was not found. It needs to be stored in the global context.
7527 ASSERT(attributes == ABSENT); 7515 ASSERT(attributes == ABSENT);
7528 attributes = NONE; 7516 attributes = NONE;
7529 context_ext = Handle<JSObject>(isolate->context()->global()); 7517 context_ext = Handle<JSObject>(isolate->context()->global());
7530 } 7518 }
7531 7519
7532 // Set the property, but ignore if read_only variable on the context 7520 // Set the property, but ignore if read_only variable on the context
7533 // extension object itself. 7521 // extension object itself.
7534 if ((attributes & READ_ONLY) == 0 || 7522 if ((attributes & READ_ONLY) == 0 ||
7535 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { 7523 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
7536 Handle<Object> set = SetProperty(context_ext, name, value, attributes); 7524 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
7537 if (set.is_null()) { 7525 if (set.is_null()) {
7538 // Failure::Exception is converted to a null handle in the 7526 // Failure::Exception is converted to a null handle in the
7539 // handle-based methods such as SetProperty. We therefore need 7527 // handle-based methods such as SetProperty. We therefore need
7540 // to convert null handles back to exceptions. 7528 // to convert null handles back to exceptions.
7541 ASSERT(isolate->has_pending_exception()); 7529 ASSERT(isolate->has_pending_exception());
7542 return Failure::Exception(); 7530 return Failure::Exception();
7543 } 7531 }
7544 } 7532 }
7545 return *value; 7533 return *value;
7546 } 7534 }
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after
8014 Object* allocation; 8002 Object* allocation;
8015 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size); 8003 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
8016 if (maybe_allocation->ToObject(&allocation)) { 8004 if (maybe_allocation->ToObject(&allocation)) {
8017 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size); 8005 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
8018 } 8006 }
8019 return maybe_allocation; 8007 return maybe_allocation;
8020 } 8008 }
8021 } 8009 }
8022 8010
8023 8011
8024 // Push an array unto an array of arrays if it is not already in the 8012 // Push an object unto an array of objects if it is not already in the
8025 // array. Returns true if the element was pushed on the stack and 8013 // array. Returns true if the element was pushed on the stack and
8026 // false otherwise. 8014 // false otherwise.
8027 static MaybeObject* Runtime_PushIfAbsent(RUNTIME_CALLING_CONVENTION) { 8015 static MaybeObject* Runtime_PushIfAbsent(RUNTIME_CALLING_CONVENTION) {
8028 RUNTIME_GET_ISOLATE; 8016 RUNTIME_GET_ISOLATE;
8029 ASSERT(args.length() == 2); 8017 ASSERT(args.length() == 2);
8030 CONVERT_CHECKED(JSArray, array, args[0]); 8018 CONVERT_CHECKED(JSArray, array, args[0]);
8031 CONVERT_CHECKED(JSArray, element, args[1]); 8019 CONVERT_CHECKED(JSObject, element, args[1]);
8032 RUNTIME_ASSERT(array->HasFastElements()); 8020 RUNTIME_ASSERT(array->HasFastElements());
8033 int length = Smi::cast(array->length())->value(); 8021 int length = Smi::cast(array->length())->value();
8034 FixedArray* elements = FixedArray::cast(array->elements()); 8022 FixedArray* elements = FixedArray::cast(array->elements());
8035 for (int i = 0; i < length; i++) { 8023 for (int i = 0; i < length; i++) {
8036 if (elements->get(i) == element) return isolate->heap()->false_value(); 8024 if (elements->get(i) == element) return isolate->heap()->false_value();
8037 } 8025 }
8038 Object* obj; 8026 Object* obj;
8039 { MaybeObject* maybe_obj = array->SetFastElement(length, element); 8027 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
8040 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 8028 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8041 } 8029 }
(...skipping 2075 matching lines...) Expand 10 before | Expand all | Expand 10 after
10117 // This function and the context acts as replacements for the function on the 10105 // This function and the context acts as replacements for the function on the
10118 // stack frame presenting the same view of the values of parameters and 10106 // stack frame presenting the same view of the values of parameters and
10119 // local variables as if the piece of JavaScript was evaluated at the point 10107 // local variables as if the piece of JavaScript was evaluated at the point
10120 // where the function on the stack frame is currently stopped. 10108 // where the function on the stack frame is currently stopped.
10121 static MaybeObject* Runtime_DebugEvaluate(RUNTIME_CALLING_CONVENTION) { 10109 static MaybeObject* Runtime_DebugEvaluate(RUNTIME_CALLING_CONVENTION) {
10122 RUNTIME_GET_ISOLATE; 10110 RUNTIME_GET_ISOLATE;
10123 HandleScope scope(isolate); 10111 HandleScope scope(isolate);
10124 10112
10125 // Check the execution state and decode arguments frame and source to be 10113 // Check the execution state and decode arguments frame and source to be
10126 // evaluated. 10114 // evaluated.
10127 ASSERT(args.length() == 4); 10115 ASSERT(args.length() == 5);
10128 Object* check_result; 10116 Object* check_result;
10129 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args, 10117 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10130 isolate); 10118 isolate);
10131 if (!maybe_check_result->ToObject(&check_result)) { 10119 if (!maybe_check_result->ToObject(&check_result)) {
10132 return maybe_check_result; 10120 return maybe_check_result;
10133 } 10121 }
10134 } 10122 }
10135 CONVERT_CHECKED(Smi, wrapped_id, args[1]); 10123 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10136 CONVERT_ARG_CHECKED(String, source, 2); 10124 CONVERT_ARG_CHECKED(String, source, 2);
10137 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); 10125 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
10126 Handle<Object> additional_context(args[4]);
10138 10127
10139 // Handle the processing of break. 10128 // Handle the processing of break.
10140 DisableBreak disable_break_save(disable_break); 10129 DisableBreak disable_break_save(disable_break);
10141 10130
10142 // Get the frame where the debugging is performed. 10131 // Get the frame where the debugging is performed.
10143 StackFrame::Id id = UnwrapFrameId(wrapped_id); 10132 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10144 JavaScriptFrameIterator it(id); 10133 JavaScriptFrameIterator it(id);
10145 JavaScriptFrame* frame = it.frame(); 10134 JavaScriptFrame* frame = it.frame();
10146 Handle<JSFunction> function(JSFunction::cast(frame->function())); 10135 Handle<JSFunction> function(JSFunction::cast(frame->function()));
10147 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); 10136 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
10180 // object build. 10169 // object build.
10181 Handle<Context> context = 10170 Handle<Context> context =
10182 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, 10171 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10183 go_between); 10172 go_between);
10184 context->set_extension(*local_scope); 10173 context->set_extension(*local_scope);
10185 // Copy any with contexts present and chain them in front of this context. 10174 // Copy any with contexts present and chain them in front of this context.
10186 Handle<Context> frame_context(Context::cast(frame->context())); 10175 Handle<Context> frame_context(Context::cast(frame->context()));
10187 Handle<Context> function_context(frame_context->fcontext()); 10176 Handle<Context> function_context(frame_context->fcontext());
10188 context = CopyWithContextChain(frame_context, context); 10177 context = CopyWithContextChain(frame_context, context);
10189 10178
10179 if (additional_context->IsJSObject()) {
10180 context = isolate->factory()->NewWithContext(context,
10181 Handle<JSObject>::cast(additional_context), false);
10182 }
10183
10190 // Wrap the evaluation statement in a new function compiled in the newly 10184 // Wrap the evaluation statement in a new function compiled in the newly
10191 // created context. The function has one parameter which has to be called 10185 // created context. The function has one parameter which has to be called
10192 // 'arguments'. This it to have access to what would have been 'arguments' in 10186 // 'arguments'. This it to have access to what would have been 'arguments' in
10193 // the function being debugged. 10187 // the function being debugged.
10194 // function(arguments,__source__) {return eval(__source__);} 10188 // function(arguments,__source__) {return eval(__source__);}
10195 10189
10196 Handle<String> function_source = 10190 Handle<String> function_source =
10197 isolate->factory()->NewStringFromAscii( 10191 isolate->factory()->NewStringFromAscii(
10198 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1)); 10192 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
10199 Handle<SharedFunctionInfo> shared = 10193 Handle<SharedFunctionInfo> shared =
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
10234 return *result; 10228 return *result;
10235 } 10229 }
10236 10230
10237 10231
10238 static MaybeObject* Runtime_DebugEvaluateGlobal(RUNTIME_CALLING_CONVENTION) { 10232 static MaybeObject* Runtime_DebugEvaluateGlobal(RUNTIME_CALLING_CONVENTION) {
10239 RUNTIME_GET_ISOLATE; 10233 RUNTIME_GET_ISOLATE;
10240 HandleScope scope(isolate); 10234 HandleScope scope(isolate);
10241 10235
10242 // Check the execution state and decode arguments frame and source to be 10236 // Check the execution state and decode arguments frame and source to be
10243 // evaluated. 10237 // evaluated.
10244 ASSERT(args.length() == 3); 10238 ASSERT(args.length() == 4);
10245 Object* check_result; 10239 Object* check_result;
10246 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args, 10240 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10247 isolate); 10241 isolate);
10248 if (!maybe_check_result->ToObject(&check_result)) { 10242 if (!maybe_check_result->ToObject(&check_result)) {
10249 return maybe_check_result; 10243 return maybe_check_result;
10250 } 10244 }
10251 } 10245 }
10252 CONVERT_ARG_CHECKED(String, source, 1); 10246 CONVERT_ARG_CHECKED(String, source, 1);
10253 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]); 10247 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
10248 Handle<Object> additional_context(args[3]);
10254 10249
10255 // Handle the processing of break. 10250 // Handle the processing of break.
10256 DisableBreak disable_break_save(disable_break); 10251 DisableBreak disable_break_save(disable_break);
10257 10252
10258 // Enter the top context from before the debugger was invoked. 10253 // Enter the top context from before the debugger was invoked.
10259 SaveContext save(isolate); 10254 SaveContext save(isolate);
10260 SaveContext* top = &save; 10255 SaveContext* top = &save;
10261 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { 10256 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
10262 top = top->prev(); 10257 top = top->prev();
10263 } 10258 }
10264 if (top != NULL) { 10259 if (top != NULL) {
10265 isolate->set_context(*top->context()); 10260 isolate->set_context(*top->context());
10266 } 10261 }
10267 10262
10268 // Get the global context now set to the top context from before the 10263 // Get the global context now set to the top context from before the
10269 // debugger was invoked. 10264 // debugger was invoked.
10270 Handle<Context> context = isolate->global_context(); 10265 Handle<Context> context = isolate->global_context();
10271 10266
10267 bool is_global = true;
10268
10269 if (additional_context->IsJSObject()) {
10270 // Create a function context first, than put 'with' context on top of it.
10271 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10272 isolate->factory()->empty_string(),
10273 isolate->factory()->undefined_value());
10274 go_between->set_context(*context);
10275 context =
10276 isolate->factory()->NewFunctionContext(
10277 Context::MIN_CONTEXT_SLOTS, go_between);
10278 context->set_extension(JSObject::cast(*additional_context));
10279 is_global = false;
10280 }
10281
10272 // Compile the source to be evaluated. 10282 // Compile the source to be evaluated.
10273 Handle<SharedFunctionInfo> shared = 10283 Handle<SharedFunctionInfo> shared =
10274 Compiler::CompileEval(source, 10284 Compiler::CompileEval(source,
10275 context, 10285 context,
10276 true); 10286 is_global);
10277 if (shared.is_null()) return Failure::Exception(); 10287 if (shared.is_null()) return Failure::Exception();
10278 Handle<JSFunction> compiled_function = 10288 Handle<JSFunction> compiled_function =
10279 Handle<JSFunction>( 10289 Handle<JSFunction>(
10280 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 10290 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10281 context)); 10291 context));
10282 10292
10283 // Invoke the result of the compilation to get the evaluation function. 10293 // Invoke the result of the compilation to get the evaluation function.
10284 bool has_pending_exception; 10294 bool has_pending_exception;
10285 Handle<Object> receiver = isolate->global(); 10295 Handle<Object> receiver = isolate->global();
10286 Handle<Object> result = 10296 Handle<Object> result =
(...skipping 984 matching lines...) Expand 10 before | Expand all | Expand 10 after
11271 } else { 11281 } else {
11272 // Handle last resort GC and make sure to allow future allocations 11282 // Handle last resort GC and make sure to allow future allocations
11273 // to grow the heap without causing GCs (if possible). 11283 // to grow the heap without causing GCs (if possible).
11274 COUNTERS->gc_last_resort_from_js()->Increment(); 11284 COUNTERS->gc_last_resort_from_js()->Increment();
11275 HEAP->CollectAllGarbage(false); 11285 HEAP->CollectAllGarbage(false);
11276 } 11286 }
11277 } 11287 }
11278 11288
11279 11289
11280 } } // namespace v8::internal 11290 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698