diff options
Diffstat (limited to 'deps/v8/src/runtime.cc')
-rw-r--r-- | deps/v8/src/runtime.cc | 427 |
1 files changed, 167 insertions, 260 deletions
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index fc6ca762f..43a673423 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -98,7 +98,7 @@ namespace internal { static StaticResource<StringInputBuffer> runtime_string_input_buffer; -static Object* DeepCopyBoilerplate(JSObject* boilerplate) { +MUST_USE_RESULT static Object* DeepCopyBoilerplate(JSObject* boilerplate) { StackLimitCheck check; if (check.HasOverflowed()) return Top::StackOverflow(); @@ -160,13 +160,22 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) { switch (copy->GetElementsKind()) { case JSObject::FAST_ELEMENTS: { FixedArray* elements = FixedArray::cast(copy->elements()); - for (int i = 0; i < elements->length(); i++) { - Object* value = elements->get(i); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - result = DeepCopyBoilerplate(js_object); - if (result->IsFailure()) return result; - elements->set(i, result); + if (elements->map() == Heap::fixed_cow_array_map()) { + Counters::cow_arrays_created_runtime.Increment(); +#ifdef DEBUG + for (int i = 0; i < elements->length(); i++) { + ASSERT(!elements->get(i)->IsJSObject()); + } +#endif + } else { + for (int i = 0; i < elements->length(); i++) { + Object* value = elements->get(i); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + result = DeepCopyBoilerplate(js_object); + if (result->IsFailure()) return result; + elements->set(i, result); + } } } break; @@ -343,18 +352,29 @@ static Handle<Object> CreateArrayLiteralBoilerplate( JSFunction::GlobalContextFromLiterals(*literals)->array_function()); Handle<Object> object = Factory::NewJSObject(constructor); - Handle<Object> copied_elements = Factory::CopyFixedArray(elements); + const bool is_cow = (elements->map() == Heap::fixed_cow_array_map()); + Handle<FixedArray> copied_elements = + is_cow ? elements : Factory::CopyFixedArray(elements); Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); - for (int i = 0; i < content->length(); i++) { - if (content->get(i)->IsFixedArray()) { - // The value contains the constant_properties of a - // simple object literal. - Handle<FixedArray> fa(FixedArray::cast(content->get(i))); - Handle<Object> result = - CreateLiteralBoilerplate(literals, fa); - if (result.is_null()) return result; - content->set(i, *result); + if (is_cow) { +#ifdef DEBUG + // Copy-on-write arrays must be shallow (and simple). + for (int i = 0; i < content->length(); i++) { + ASSERT(!content->get(i)->IsFixedArray()); + } +#endif + } else { + for (int i = 0; i < content->length(); i++) { + if (content->get(i)->IsFixedArray()) { + // The value contains the constant_properties of a + // simple object literal. + Handle<FixedArray> fa(FixedArray::cast(content->get(i))); + Handle<Object> result = + CreateLiteralBoilerplate(literals, fa); + if (result.is_null()) return result; + content->set(i, *result); + } } } @@ -483,6 +503,10 @@ static Object* Runtime_CreateArrayLiteralShallow(Arguments args) { // Update the functions literal and return the boilerplate. literals->set(literals_index, *boilerplate); } + if (JSObject::cast(*boilerplate)->elements()->map() == + Heap::fixed_cow_array_map()) { + Counters::cow_arrays_created_runtime.Increment(); + } return Heap::CopyJSObject(JSObject::cast(*boilerplate)); } @@ -956,7 +980,9 @@ static Object* Runtime_DeclareContextSlot(Arguments args) { context->set(index, *initial_value); } } else { - Handle<JSObject>::cast(holder)->SetElement(index, *initial_value); + // The holder is an arguments object. + Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); + SetElement(arguments, index, initial_value); } } else { // Slow case: The property is not in the FixedArray part of the context. @@ -1214,7 +1240,8 @@ static Object* Runtime_InitializeConstContextSlot(Arguments args) { } else { // The holder is an arguments object. ASSERT((attributes & READ_ONLY) == 0); - Handle<JSObject>::cast(holder)->SetElement(index, *value); + Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); + SetElement(arguments, index, value); } return *value; } @@ -1340,6 +1367,63 @@ static Object* Runtime_RegExpConstructResult(Arguments args) { } +static Object* Runtime_RegExpCloneResult(Arguments args) { + ASSERT(args.length() == 1); + Map* regexp_result_map; + { + AssertNoAllocation no_gc; + HandleScope handles; + regexp_result_map = Top::global_context()->regexp_result_map(); + } + if (!args[0]->IsJSArray()) return args[0]; + + JSArray* result = JSArray::cast(args[0]); + // Arguments to RegExpCloneResult should always be fresh RegExp exec call + // results (either a fresh JSRegExpResult or null). + // If the argument is not a JSRegExpResult, or isn't unmodified, just return + // the argument uncloned. + if (result->map() != regexp_result_map) return result; + + // Having the original JSRegExpResult map guarantees that we have + // fast elements and no properties except the two in-object properties. + ASSERT(result->HasFastElements()); + ASSERT(result->properties() == Heap::empty_fixed_array()); + ASSERT_EQ(2, regexp_result_map->inobject_properties()); + + Object* new_array_alloc = Heap::AllocateRaw(JSRegExpResult::kSize, + NEW_SPACE, + OLD_POINTER_SPACE); + if (new_array_alloc->IsFailure()) return new_array_alloc; + + // Set HeapObject map to JSRegExpResult map. + reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map); + + JSArray* new_array = JSArray::cast(new_array_alloc); + + // Copy JSObject properties. + new_array->set_properties(result->properties()); // Empty FixedArray. + + // Copy JSObject elements as copy-on-write. + FixedArray* elements = FixedArray::cast(result->elements()); + if (elements != Heap::empty_fixed_array()) { + elements->set_map(Heap::fixed_cow_array_map()); + } + new_array->set_elements(elements); + + // Copy JSArray length. + new_array->set_length(result->length()); + + // Copy JSRegExpResult in-object property fields input and index. + new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex, + result->FastPropertyAt( + JSRegExpResult::kIndexIndex)); + new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex, + result->FastPropertyAt( + JSRegExpResult::kInputIndex)); + return new_array; +} + + static Object* Runtime_RegExpInitializeObject(Arguments args) { AssertNoAllocation no_alloc; ASSERT(args.length() == 5); @@ -1620,7 +1704,6 @@ static Object* Runtime_SetCode(Arguments args) { RUNTIME_ASSERT(code->IsJSFunction()); Handle<JSFunction> fun = Handle<JSFunction>::cast(code); Handle<SharedFunctionInfo> shared(fun->shared()); - SetExpectedNofProperties(target, shared->expected_nof_properties()); if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { return Failure::Exception(); @@ -1665,6 +1748,17 @@ static Object* Runtime_SetCode(Arguments args) { } +static Object* Runtime_SetExpectedNumberOfProperties(Arguments args) { + HandleScope scope; + ASSERT(args.length() == 2); + CONVERT_ARG_CHECKED(JSFunction, function, 0); + CONVERT_SMI_CHECKED(num, args[1]); + RUNTIME_ASSERT(num >= 0); + SetExpectedNofProperties(function, num); + return Heap::undefined_value(); +} + + static Object* CharFromCode(Object* char_code) { uint32_t code; if (char_code->ToArrayIndex(&code)) { @@ -2724,40 +2818,6 @@ static int BoyerMooreIndexOf(Vector<const schar> subject, } -template <typename schar> -static inline int SingleCharIndexOf(Vector<const schar> string, - schar pattern_char, - int start_index) { - if (sizeof(schar) == 1) { - const schar* pos = reinterpret_cast<const schar*>( - memchr(string.start() + start_index, - pattern_char, - string.length() - start_index)); - if (pos == NULL) return -1; - return static_cast<int>(pos - string.start()); - } - for (int i = start_index, n = string.length(); i < n; i++) { - if (pattern_char == string[i]) { - return i; - } - } - return -1; -} - - -template <typename schar> -static int SingleCharLastIndexOf(Vector<const schar> string, - schar pattern_char, - int start_index) { - for (int i = start_index; i >= 0; i--) { - if (pattern_char == string[i]) { - return i; - } - } - return -1; -} - - // Trivial string search for shorter strings. // On return, if "complete" is set to true, the return value is the // final result of searching for the patter in the subject. @@ -2769,6 +2829,7 @@ static int SimpleIndexOf(Vector<const schar> subject, Vector<const pchar> pattern, int idx, bool* complete) { + ASSERT(pattern.length() > 1); // Badness is a count of how much work we have done. When we have // done enough work we decide it's probably worth switching to a better // algorithm. @@ -2831,12 +2892,12 @@ static int SimpleIndexOf(Vector<const schar> subject, if (subject[i] != pattern_first_char) continue; } int j = 1; - do { + while (j < pattern.length()) { if (pattern[j] != subject[i+j]) { break; } j++; - } while (j < pattern.length()); + } if (j == pattern.length()) { return i; } @@ -2852,7 +2913,6 @@ enum StringSearchStrategy { SEARCH_FAIL, SEARCH_SHORT, SEARCH_LONG }; template <typename pchar> static inline StringSearchStrategy InitializeStringSearch( Vector<const pchar> pat, bool ascii_subject) { - ASSERT(pat.length() > 1); // We have an ASCII haystack and a non-ASCII needle. Check if there // really is a non-ASCII character in the needle and bail out if there // is. @@ -2938,54 +2998,15 @@ int Runtime::StringMatch(Handle<String> sub, int subject_length = sub->length(); if (start_index + pattern_length > subject_length) return -1; - if (!sub->IsFlat()) { - FlattenString(sub); - } - - // Searching for one specific character is common. For one - // character patterns linear search is necessary, so any smart - // algorithm is unnecessary overhead. - if (pattern_length == 1) { - AssertNoAllocation no_heap_allocation; // ensure vectors stay valid - String* seq_sub = *sub; - if (seq_sub->IsConsString()) { - seq_sub = ConsString::cast(seq_sub)->first(); - } - if (seq_sub->IsAsciiRepresentation()) { - uc16 pchar = pat->Get(0); - if (pchar > String::kMaxAsciiCharCode) { - return -1; - } - Vector<const char> ascii_vector = - seq_sub->ToAsciiVector().SubVector(start_index, subject_length); - const void* pos = memchr(ascii_vector.start(), - static_cast<const char>(pchar), - static_cast<size_t>(ascii_vector.length())); - if (pos == NULL) { - return -1; - } - return static_cast<int>(reinterpret_cast<const char*>(pos) - - ascii_vector.start() + start_index); - } - return SingleCharIndexOf(seq_sub->ToUC16Vector(), - pat->Get(0), - start_index); - } - - if (!pat->IsFlat()) { - FlattenString(pat); - } + if (!sub->IsFlat()) FlattenString(sub); + if (!pat->IsFlat()) FlattenString(pat); AssertNoAllocation no_heap_allocation; // ensure vectors stay valid // Extract flattened substrings of cons strings before determining asciiness. String* seq_sub = *sub; - if (seq_sub->IsConsString()) { - seq_sub = ConsString::cast(seq_sub)->first(); - } + if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first(); String* seq_pat = *pat; - if (seq_pat->IsConsString()) { - seq_pat = ConsString::cast(seq_pat)->first(); - } + if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first(); // dispatch on type of strings if (seq_pat->IsAsciiRepresentation()) { @@ -3075,30 +3096,8 @@ static Object* Runtime_StringLastIndexOf(Arguments args) { return Smi::FromInt(start_index); } - if (!sub->IsFlat()) { - FlattenString(sub); - } - - if (pat_length == 1) { - AssertNoAllocation no_heap_allocation; // ensure vectors stay valid - if (sub->IsAsciiRepresentation()) { - uc16 pchar = pat->Get(0); - if (pchar > String::kMaxAsciiCharCode) { - return Smi::FromInt(-1); - } - return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(), - static_cast<char>(pat->Get(0)), - start_index)); - } else { - return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(), - pat->Get(0), - start_index)); - } - } - - if (!pat->IsFlat()) { - FlattenString(pat); - } + if (!sub->IsFlat()) FlattenString(sub); + if (!pat->IsFlat()) FlattenString(pat); AssertNoAllocation no_heap_allocation; // ensure vectors stay valid @@ -3276,88 +3275,6 @@ static void SetLastMatchInfoNoCaptures(Handle<String> subject, } -template <typename schar> -static bool SearchCharMultiple(Vector<schar> subject, - String* pattern, - schar pattern_char, - FixedArrayBuilder* builder, - int* match_pos) { - // Position of last match. - int pos = *match_pos; - int subject_length = subject.length(); - while (pos < subject_length) { - int match_end = pos + 1; - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); - if (new_pos >= 0) { - // Match has been found. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } - } - if (pos + 1 < subject_length) { - ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); - } - *match_pos = pos; - return true; -} - - -static bool SearchCharMultiple(Handle<String> subject, - Handle<String> pattern, - Handle<JSArray> last_match_info, - FixedArrayBuilder* builder) { - ASSERT(subject->IsFlat()); - ASSERT_EQ(1, pattern->length()); - uc16 pattern_char = pattern->Get(0); - // Treating position before first as initial "previous match position". - int match_pos = -1; - - for (;;) { // Break when search complete. - builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); - AssertNoAllocation no_gc; - if (subject->IsAsciiRepresentation()) { - if (pattern_char > String::kMaxAsciiCharCode) { - break; - } - Vector<const char> subject_vector = subject->ToAsciiVector(); - char pattern_ascii_char = static_cast<char>(pattern_char); - bool complete = SearchCharMultiple<const char>(subject_vector, - *pattern, - pattern_ascii_char, - builder, - &match_pos); - if (complete) break; - } else { - Vector<const uc16> subject_vector = subject->ToUC16Vector(); - bool complete = SearchCharMultiple<const uc16>(subject_vector, - *pattern, - pattern_char, - builder, - &match_pos); - if (complete) break; - } - } - - if (match_pos >= 0) { - SetLastMatchInfoNoCaptures(subject, - last_match_info, - match_pos, - match_pos + 1); - return true; - } - return false; // No matches at all. -} - - template <typename schar, typename pchar> static bool SearchStringMultiple(Vector<schar> subject, String* pattern, @@ -3435,7 +3352,6 @@ static bool SearchStringMultiple(Handle<String> subject, FixedArrayBuilder* builder) { ASSERT(subject->IsFlat()); ASSERT(pattern->IsFlat()); - ASSERT(pattern->length() > 1); // Treating as if a previous match was before first character. int match_pos = -pattern->length(); @@ -3500,7 +3416,7 @@ static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; OffsetsVector registers(required_registers); - Vector<int> register_vector(registers.vector(), registers.length()); + Vector<int32_t> register_vector(registers.vector(), registers.length()); int subject_length = subject->length(); for (;;) { // Break on failure, return on exception. @@ -3562,7 +3478,7 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; OffsetsVector registers(required_registers); - Vector<int> register_vector(registers.vector(), registers.length()); + Vector<int32_t> register_vector(registers.vector(), registers.length()); RegExpImpl::IrregexpResult result = RegExpImpl::IrregexpExecOnce(regexp, @@ -3622,7 +3538,7 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( } // Swap register vectors, so the last successful match is in // prev_register_vector. - Vector<int> tmp = prev_register_vector; + Vector<int32_t> tmp = prev_register_vector; prev_register_vector = register_vector; register_vector = tmp; @@ -3693,14 +3609,6 @@ static Object* Runtime_RegExpExecMultiple(Arguments args) { if (regexp->TypeTag() == JSRegExp::ATOM) { Handle<String> pattern( String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); - int pattern_length = pattern->length(); - if (pattern_length == 1) { - if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { - return *builder.ToJSArray(result_array); - } - return Heap::null_value(); - } - if (!pattern->IsFlat()) FlattenString(pattern); if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { return *builder.ToJSArray(result_array); @@ -4014,7 +3922,8 @@ static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) { if (result.IsProperty() && (result.type() == FIELD || result.type() == NORMAL || result.type() == CONSTANT_FUNCTION)) { - obj->DeleteProperty(name, JSObject::NORMAL_DELETION); + Object* ok = obj->DeleteProperty(name, JSObject::NORMAL_DELETION); + if (ok->IsFailure()) return ok; } return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr); } @@ -4763,6 +4672,18 @@ static Object* Runtime_StringToNumber(Arguments args) { if (minus) { if (d == 0) return Heap::minus_zero_value(); d = -d; + } else if (!subject->HasHashCode() && + len <= String::kMaxArrayIndexSize && + (len == 1 || data[0] != '0')) { + // String hash is not calculated yet but all the data are present. + // Update the hash field to speed up sequential convertions. + uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); +#ifdef DEBUG + subject->Hash(); // Force hash calculation. + ASSERT_EQ(static_cast<int>(subject->hash_field()), + static_cast<int>(hash)); +#endif + subject->set_hash_field(hash); } return Smi::FromInt(d); } @@ -5288,23 +5209,6 @@ void FindStringIndices(Vector<const schar> subject, } } -template <typename schar> -inline void FindCharIndices(Vector<const schar> subject, - const schar pattern_char, - ZoneList<int>* indices, - unsigned int limit) { - // Collect indices of pattern_char in subject, and the end-of-string index. - // Stop after finding at most limit values. - int index = 0; - while (limit > 0) { - index = SingleCharIndexOf(subject, pattern_char, index); - if (index < 0) return; - indices->Add(index); - index++; - limit--; - } -} - static Object* Runtime_StringSplit(Arguments args) { ASSERT(args.length() == 3); @@ -5330,22 +5234,10 @@ static Object* Runtime_StringSplit(Arguments args) { // Find (up to limit) indices of separator and end-of-string in subject int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); ZoneList<int> indices(initial_capacity); - if (pattern_length == 1) { - // Special case, go directly to fast single-character split. - AssertNoAllocation nogc; - uc16 pattern_char = pattern->Get(0); - if (subject->IsTwoByteRepresentation()) { - FindCharIndices(subject->ToUC16Vector(), pattern_char, - &indices, - limit); - } else if (pattern_char <= String::kMaxAsciiCharCode) { - FindCharIndices(subject->ToAsciiVector(), - static_cast<char>(pattern_char), - &indices, - limit); - } - } else { - if (!pattern->IsFlat()) FlattenString(pattern); + if (!pattern->IsFlat()) FlattenString(pattern); + + // No allocation block. + { AssertNoAllocation nogc; if (subject->IsAsciiRepresentation()) { Vector<const char> subject_vector = subject->ToAsciiVector(); @@ -5375,11 +5267,12 @@ static Object* Runtime_StringSplit(Arguments args) { } } } + if (static_cast<uint32_t>(indices.length()) < limit) { indices.Add(subject_length); } - // The list indices now contains the end of each part to create. + // The list indices now contains the end of each part to create. // Create JSArray of substrings separated by separator. int part_count = indices.length(); @@ -5484,6 +5377,14 @@ static Object* Runtime_StringToArray(Arguments args) { } +static Object* Runtime_NewStringWrapper(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 1); + CONVERT_CHECKED(String, value, args[0]); + return value->ToObject(); +} + + bool Runtime::IsUpperCaseChar(uint16_t ch) { unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; int char_length = to_upper_mapping.get(ch, 0, chars); @@ -6699,9 +6600,13 @@ static Object* Runtime_DateYMDFromTime(Arguments args) { int year, month, day; DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day); - res_array->SetElement(0, Smi::FromInt(year)); - res_array->SetElement(1, Smi::FromInt(month)); - res_array->SetElement(2, Smi::FromInt(day)); + RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map()); + FixedArray* elms = FixedArray::cast(res_array->elements()); + RUNTIME_ASSERT(elms->length() == 3); + + elms->set(0, Smi::FromInt(year)); + elms->set(1, Smi::FromInt(month)); + elms->set(2, Smi::FromInt(day)); return Heap::undefined_value(); } @@ -8057,7 +7962,8 @@ static Object* Runtime_MoveArrayContents(Arguments args) { CONVERT_CHECKED(JSArray, to, args[1]); HeapObject* new_elements = from->elements(); Object* new_map; - if (new_elements->map() == Heap::fixed_array_map()) { + if (new_elements->map() == Heap::fixed_array_map() || + new_elements->map() == Heap::fixed_cow_array_map()) { new_map = to->map()->GetFastElementsMap(); } else { new_map = to->map()->GetSlowElementsMap(); @@ -10602,9 +10508,10 @@ Runtime::Function* Runtime::FunctionForId(FunctionId fid) { } -Runtime::Function* Runtime::FunctionForName(const char* name) { +Runtime::Function* Runtime::FunctionForName(Vector<const char> name) { for (Function* f = Runtime_functions; f->name != NULL; f++) { - if (strcmp(f->name, name) == 0) { + if (strncmp(f->name, name.start(), name.length()) == 0 + && f->name[name.length()] == 0) { return f; } } |