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

全部博文(70)

分类: 信息化

2014-05-06 16:35:43

一、rumtime.js

function ADD(x) {
    // Fast case: Check for number operands and do the addition.
    if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
    if (IS_STRING(this) && IS_STRING(x)) return %_StringAdd(this, x);
    
    // Default implementation.
    var a = %ToPrimitive(this, NO_HINT);
    var b = %ToPrimitive(x, NO_HINT);
    
    if (IS_STRING(a)) {
        return %_StringAdd(a, %ToString(b));
        } else if (IS_STRING(b)) {
        return %_StringAdd(%NonStringToString(a), b);
        } else {
        return %NumberAdd(%ToNumber(a), %ToNumber(b));
    }
}


// Left operand (this) is already a string.
function STRING_ADD_LEFT(y) {
    if (!IS_STRING(y)) {
        if (IS_STRING_WRAPPER(y) && %_IsStringWrapperSafeForDefaultValueOf(y)) {
            y = %_ValueOf(y);
            } else {
            y = IS_NUMBER(y)
            ? %_NumberToString(y)
            : %ToString(%ToPrimitive(y, NO_HINT));
        }
    }
    return %_StringAdd(this, y);
}


// Right operand (y) is already a string.
function STRING_ADD_RIGHT(y) {
    var x = this;
    if (!IS_STRING(x)) {
        if (IS_STRING_WRAPPER(x) && %_IsStringWrapperSafeForDefaultValueOf(x)) {
            x = %_ValueOf(x);
            } else {
            x = IS_NUMBER(x)
            ? %_NumberToString(x)
            : %ToString(%ToPrimitive(x, NO_HINT));
        }
    }
    return %_StringAdd(x, y);
}

二、调用 %_StringAdd(x, y),它在 rumtime.cc 内。

RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
    NoHandleAllocation ha;
    ASSERT(args.length() == 2);
    CONVERT_CHECKED(String, str1, args[0]);
    CONVERT_CHECKED(String, str2, args[1]);
    isolate->counters()->string_add_runtime()->Increment();
    return isolate->heap()->AllocateConsString(str1, str2);
}

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

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

三、调用 AllocateConsString 连接两字符串,它在 heap.cc 内。

MaybeObject* Heap::AllocateConsString(String* first, String* second) {
    int first_length = first->length();
    if (first_length == 0) {
        return second;
    }
    
    int second_length = second->length();
    if (second_length == 0) {
        return first;
    }
    
    int length = first_length + second_length;
    
    // Optimization for 2-byte strings often used as keys in a decompression
    // dictionary. Check whether we already have the string in the symbol
    // table to prevent creation of many unneccesary strings.
    if (length == 2) {
        unsigned c1 = first->Get(0);
        unsigned c2 = second->Get(0);
        return MakeOrFindTwoCharacterString(this, c1, c2);
    }
    
    bool first_is_ascii = first->IsAsciiRepresentation();
    bool second_is_ascii = second->IsAsciiRepresentation();
    bool is_ascii = first_is_ascii && second_is_ascii;
    
    // Make sure that an out of memory exception is thrown if the length
    // of the new cons string is too large.
    if (length > String::kMaxLength || length < 0) {
        isolate()->context()->mark_out_of_memory();
        return Failure::OutOfMemoryException();
    }
    
    bool is_ascii_data_in_two_byte_string = false;
    if (!is_ascii) {
        // At least one of the strings uses two-byte representation so we
        // can't use the fast case code for short ascii strings below, but
        // we can try to save memory if all chars actually fit in ascii.
        is_ascii_data_in_two_byte_string =
        first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
        if (is_ascii_data_in_two_byte_string) {
            isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
        }
    }
    
    // If the resulting string is small make a flat string.
    if (length < String::kMinNonFlatLength) {
        ASSERT(first->IsFlat());
        ASSERT(second->IsFlat());
        if (is_ascii) {
            Object* result;
            { MaybeObject* maybe_result = AllocateRawAsciiString(length);
                if (!maybe_result->ToObject(&result)) return maybe_result;
            }
            // Copy the characters into the new object.
            char* dest = SeqAsciiString::cast(result)->GetChars();
            // Copy first part.
            const char* src;
            if (first->IsExternalString()) {
                src = ExternalAsciiString::cast(first)->resource()->data();
                } else {
                src = SeqAsciiString::cast(first)->GetChars();
            }
            for (int i = 0; i < first_length; i++) *dest++ = src[i];
            // Copy second part.
            if (second->IsExternalString()) {
                src = ExternalAsciiString::cast(second)->resource()->data();
                } else {
                src = SeqAsciiString::cast(second)->GetChars();
            }
            for (int i = 0; i < second_length; i++) *dest++ = src[i];
            return result;
            } else {
            if (is_ascii_data_in_two_byte_string) {
                Object* result;
                { MaybeObject* maybe_result = AllocateRawAsciiString(length);
                    if (!maybe_result->ToObject(&result)) return maybe_result;
                }
                // Copy the characters into the new object.
                char* dest = SeqAsciiString::cast(result)->GetChars();
                String::WriteToFlat(first, dest, 0, first_length);
                String::WriteToFlat(second, dest + first_length, 0, second_length);
                isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
                return result;
            }
            
            Object* result;
            { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
                if (!maybe_result->ToObject(&result)) return maybe_result;
            }
            // Copy the characters into the new object.
            uc16* dest = SeqTwoByteString::cast(result)->GetChars();
            String::WriteToFlat(first, dest, 0, first_length);
            String::WriteToFlat(second, dest + first_length, 0, second_length);
            return result;
        }
    }
    
    Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
    cons_ascii_string_map() : cons_string_map();
    
    Object* result;
    { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
        if (!maybe_result->ToObject(&result)) return maybe_result;
    }
    
    AssertNoAllocation no_gc;
    ConsString* cons_string = ConsString::cast(result);
    WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
    cons_string->set_length(length);
    cons_string->set_hash_field(String::kEmptyHashField);
    cons_string->set_first(first, mode);
    cons_string->set_second(second, mode);
    return result;
}

这里大致调用两种 String 连接方式 String::WriteToFlat 与 ConsString::set_first 和 ConsString::set_second。

四、String::WriteToFlat 在 object.cc 内,是个模板方法。

template <typename sinkchar>
void String::WriteToFlat(String* src,
sinkchar* sink,
int f,
int t) {
    String* source = src;
    int from = f;
    int to = t;
    while (true) {
        ASSERT(0 <= from && from <= to && to <= source->length());
        switch (StringShape(source).full_representation_tag()) {
            case kAsciiStringTag | kExternalStringTag: {
                CopyChars(sink,
                ExternalAsciiString::cast(source)->resource()->data() + from,
                to - from);
                return;
            }
            case kTwoByteStringTag | kExternalStringTag: {
                const uc16* data =
                ExternalTwoByteString::cast(source)->resource()->data();
                CopyChars(sink,
                data + from,
                to - from);
                return;
            }
            case kAsciiStringTag | kSeqStringTag: {
                CopyChars(sink,
                SeqAsciiString::cast(source)->GetChars() + from,
                to - from);
                return;
            }
            case kTwoByteStringTag | kSeqStringTag: {
                CopyChars(sink,
                SeqTwoByteString::cast(source)->GetChars() + from,
                to - from);
                return;
            }
            case kAsciiStringTag | kConsStringTag:
            case kTwoByteStringTag | kConsStringTag: {
                ConsString* cons_string = ConsString::cast(source);
                String* first = cons_string->first();
                int boundary = first->length();
                if (to - boundary >= boundary - from) {
                    // Right hand side is longer. Recurse over left.
                    if (from < boundary) {
                        WriteToFlat(first, sink, from, boundary);
                        sink += boundary - from;
                        from = 0;
                        } else {
                        from -= boundary;
                    }
                    to -= boundary;
                    source = cons_string->second();
                    } else {
                    // Left hand side is longer. Recurse over right.
                    if (to > boundary) {
                        String* second = cons_string->second();
                        WriteToFlat(second,
                        sink + boundary - from,
                        0,
                        to - boundary);
                        to = boundary;
                    }
                    source = first;
                }
                break;
            }
        }
    }
}

其中 CopyChars 在 v8utils.h 中实现,同样是模板方法。

// Copy from ASCII/16bit chars to ASCII/16bit chars.
template <typename sourcechar, typename sinkchar>
static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
    sinkchar* limit = dest + chars;
    #ifdef V8_HOST_CAN_READ_UNALIGNED
    if (sizeof(*dest) == sizeof(*src)) {
        if (chars >= static_cast<int>(OS::kMinComplexMemCopy / sizeof(*dest))) {
            OS::MemCopy(dest, src, chars * sizeof(*dest));
            return;
        }
        // Number of characters in a uintptr_t.
        static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
        while (dest <= limit - kStepSize) {
            *reinterpret_cast<uintptr_t*>(dest) =
            *reinterpret_cast<const uintptr_t*>(src);
            dest += kStepSize;
            src += kStepSize;
        }
    }
    #endif
    while (dest < limit) {
        *dest++ = static_cast<sinkchar>(*src++);
    }
}

五、 ConsString::set_first 和 ConsString::set_second,在 objects-inl.h 中实现。

void ConsString::set_first(String* value, WriteBarrierMode mode) {
    WRITE_FIELD(this, kFirstOffset, value);
    CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kFirstOffset, mode);
}

void ConsString::set_first(String* value, WriteBarrierMode mode) {
    WRITE_FIELD(this, kFirstOffset, value);
    CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kFirstOffset, mode);
}

其中 WRITE_FIELD 和 CONDITIONAL_WRITE_BARRIER 是宏,同在 objects-inl.h 中定义。

#define WRITE_FIELD(p, offset, value) \
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)

// CONDITIONAL_WRITE_BARRIER must be issued after the actual
// write due to the assert validating the written value.
#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, mode) \
if (mode == UPDATE_WRITE_BARRIER) { \
    heap->RecordWrite(object->address(), offset); \
    } else { \
    ASSERT(mode == SKIP_WRITE_BARRIER); \
    ASSERT(heap->InNewSpace(object) || \
    !heap->InNewSpace(READ_FIELD(object, offset)) || \
    Page::FromAddress(object->address())-> \
    IsRegionDirty(object->address() + offset)); \
}

同样 FIELD_ADDR 也是同文件定义的宏。

#define FIELD_ADDR(p, offset) \
(reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)

WRITE_FIELD(this, kFirstOffset, value); 语句最后转为
(*reinterpret_cast<Object**>((reinterpret_cast<byte*>(this) + kFirstOffset - kHeapObjectTag)(this, offset)) = value);
阅读(706) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~