Chinaunix首页 | 论坛 | 博客
  • 博客访问: 88143
  • 博文数量: 70
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 417
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-11 10:48
文章分类

全部博文(70)

分类: 信息化

2014-05-06 16:40:43

一、string.js 内 StringConcat 方法

// ECMA-262, section 15.5.4.6
function StringConcat() {
    if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
        throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
    }
    var len = %_ArgumentsLength();
    var this_as_string = TO_STRING_INLINE(this);
    if (len === 1) {
        return this_as_string + %_Arguments(0);
    }
    var parts = new InternalArray(len + 1);
    parts[0] = this_as_string;
    for (var i = 0; i < len; i++) {
        var part = %_Arguments(i);
        parts[i + 1] = TO_STRING_INLINE(part);
    }
    return %StringBuilderConcat(parts, len + 1, "");
}

二、调用 %StringBuilderConcat 内置方法,它在 runtime.cc 内。

RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
    NoHandleAllocation ha;
    ASSERT(args.length() == 3);
    CONVERT_CHECKED(JSArray, array, args[0]);
    if (!args[1]->IsSmi()) {
        isolate->context()->mark_out_of_memory();
        return Failure::OutOfMemoryException();
    }
    int array_length = args.smi_at(1);
    CONVERT_CHECKED(String, special, args[2]);
    
    // This assumption is used by the slice encoding in one or two smis.
    ASSERT(Smi::kMaxValue >= String::kMaxLength);
    
    int special_length = special->length();
    if (!array->HasFastElements()) {
        return isolate->Throw(isolate->heap()->illegal_argument_symbol());
    }
    FixedArray* fixed_array = FixedArray::cast(array->elements());
    if (fixed_array->length() < array_length) {
        array_length = fixed_array->length();
    }
    
    if (array_length == 0) {
        return isolate->heap()->empty_string();
        } else if (array_length == 1) {
        Object* first = fixed_array->get(0);
        if (first->IsString()) return first;
    }
    
    bool ascii = special->HasOnlyAsciiChars();
    int position = 0;
    for (int i = 0; i < array_length; i++) {
        int increment = 0;
        Object* elt = fixed_array->get(i);
        if (elt->IsSmi()) {
            // Smi encoding of position and length.
            int smi_value = Smi::cast(elt)->value();
            int pos;
            int len;
            if (smi_value > 0) {
                // Position and length encoded in one smi.
                pos = StringBuilderSubstringPosition::decode(smi_value);
                len = StringBuilderSubstringLength::decode(smi_value);
                } else {
                // Position and length encoded in two smis.
                len = -smi_value;
                // Get the position and check that it is a positive smi.
                i++;
                if (i >= array_length) {
                    return isolate->Throw(isolate->heap()->illegal_argument_symbol());
                }
                Object* next_smi = fixed_array->get(i);
                if (!next_smi->IsSmi()) {
                    return isolate->Throw(isolate->heap()->illegal_argument_symbol());
                }
                pos = Smi::cast(next_smi)->value();
                if (pos < 0) {
                    return isolate->Throw(isolate->heap()->illegal_argument_symbol());
                }
            }
            ASSERT(pos >= 0);
            ASSERT(len >= 0);
            if (pos > special_length || len > special_length - pos) {
                return isolate->Throw(isolate->heap()->illegal_argument_symbol());
            }
            increment = len;
            } else if (elt->IsString()) {
            String* element = String::cast(elt);
            int element_length = element->length();
            increment = element_length;
            if (ascii && !element->HasOnlyAsciiChars()) {
                ascii = false;
            }
            } else {
            return isolate->Throw(isolate->heap()->illegal_argument_symbol());
        }
        if (increment > String::kMaxLength - position) {
            isolate->context()->mark_out_of_memory();
            return Failure::OutOfMemoryException();
        }
        position += increment;
    }
    
    int length = position;
    Object* object;
    
    if (ascii) {
        { MaybeObject* maybe_object =
            isolate->heap()->AllocateRawAsciiString(length);
            if (!maybe_object->ToObject(&object)) return maybe_object;
        }
        SeqAsciiString* answer = SeqAsciiString::cast(object);
        StringBuilderConcatHelper(special,
        answer->GetChars(),
        fixed_array,
        array_length);
        return answer;
        } else {
        { MaybeObject* maybe_object =
            isolate->heap()->AllocateRawTwoByteString(length);
            if (!maybe_object->ToObject(&object)) return maybe_object;
        }
        SeqTwoByteString* answer = SeqTwoByteString::cast(object);
        StringBuilderConcatHelper(special,
        answer->GetChars(),
        fixed_array,
        array_length);
        return answer;
    }
}

【注】:RUNTIME_FUNCTION 是个宏,定义在 argument.h 文件内

#define RUNTIME_FUNCTION(Type, Name) \
Type Name(Arguments args, Isolate* isolate)

三、调用 StringBuilderConcatHelper ,它同在 runtime.cc 内

template <typename sinkchar>
static inline void StringBuilderConcatHelper(String* special,
sinkchar* sink,
FixedArray* fixed_array,
int array_length) {
    int position = 0;
    for (int i = 0; i < array_length; i++) {
        Object* element = fixed_array->get(i);
        if (element->IsSmi()) {
            // Smi encoding of position and length.
            int encoded_slice = Smi::cast(element)->value();
            int pos;
            int len;
            if (encoded_slice > 0) {
                // Position and length encoded in one smi.
                pos = StringBuilderSubstringPosition::decode(encoded_slice);
                len = StringBuilderSubstringLength::decode(encoded_slice);
                } else {
                // Position and length encoded in two smis.
                Object* obj = fixed_array->get(++i);
                ASSERT(obj->IsSmi());
                pos = Smi::cast(obj)->value();
                len = -encoded_slice;
            }
            String::WriteToFlat(special,
            sink + position,
            pos,
            pos + len);
            position += len;
            } else {
            String* string = String::cast(element);
            int element_length = string->length();
            String::WriteToFlat(string, sink + position, 0, element_length);
            position += element_length;
        }
    }
}

四、调用 String::WriteToFlat 
此后流程与 String + 调用 String::WriteToFlat 流程一致。
阅读(532) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~