Author: [EMAIL PROTECTED] Date: Tue Oct 28 01:56:02 2008 New Revision: 619
Added: branches/0.3/test/mjsunit/string-compare-alignment.js - copied unchanged from r611, /branches/bleeding_edge/test/mjsunit/string-compare-alignment.js Modified: branches/0.3/src/api.cc branches/0.3/src/builtins.cc branches/0.3/src/builtins.h branches/0.3/src/codegen-ia32.cc branches/0.3/src/execution.cc branches/0.3/src/ic-arm.cc branches/0.3/src/ic-ia32.cc branches/0.3/src/ic.cc branches/0.3/src/ic.h branches/0.3/src/jsregexp.cc branches/0.3/src/objects-inl.h branches/0.3/src/objects.cc branches/0.3/src/objects.h branches/0.3/src/runtime.js branches/0.3/src/stub-cache-arm.cc branches/0.3/src/stub-cache-ia32.cc branches/0.3/src/stub-cache.cc branches/0.3/src/stub-cache.h branches/0.3/src/top.cc branches/0.3/src/top.h branches/0.3/test/mjsunit/mjsunit.status Log: Merge in changes from version 0.4.1 to 0.3.7. Review URL: http://codereview.chromium.org/8653 Modified: branches/0.3/src/api.cc ============================================================================== --- branches/0.3/src/api.cc (original) +++ branches/0.3/src/api.cc Tue Oct 28 01:56:02 2008 @@ -230,7 +230,13 @@ v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) { if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>(); - i::Top::ScheduleThrow(*Utils::OpenHandle(*value)); + // If we're passed an empty handle, we throw an undefined exception + // to deal more gracefully with out of memory situations. + if (value.IsEmpty()) { + i::Top::ScheduleThrow(i::Heap::undefined_value()); + } else { + i::Top::ScheduleThrow(*Utils::OpenHandle(*value)); + } return v8::Undefined(); } @@ -2216,7 +2222,7 @@ const char* v8::V8::GetVersion() { - return "0.3.6"; + return "0.3.7"; } Modified: branches/0.3/src/builtins.cc ============================================================================== --- branches/0.3/src/builtins.cc (original) +++ branches/0.3/src/builtins.cc Tue Oct 28 01:56:02 2008 @@ -465,18 +465,8 @@ } -static void Generate_LoadIC_ShortStringLength(MacroAssembler* masm) { - LoadIC::GenerateShortStringLength(masm); -} - - -static void Generate_LoadIC_MediumStringLength(MacroAssembler* masm) { - LoadIC::GenerateMediumStringLength(masm); -} - - -static void Generate_LoadIC_LongStringLength(MacroAssembler* masm) { - LoadIC::GenerateLongStringLength(masm); +static void Generate_LoadIC_StringLength(MacroAssembler* masm) { + LoadIC::GenerateStringLength(masm); } Modified: branches/0.3/src/builtins.h ============================================================================== --- branches/0.3/src/builtins.h (original) +++ branches/0.3/src/builtins.h Tue Oct 28 01:56:02 2008 @@ -69,9 +69,7 @@ V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \ V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \ V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_ShortStringLength, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_MediumStringLength, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_LongStringLength, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \ V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \ V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \ V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \ Modified: branches/0.3/src/codegen-ia32.cc ============================================================================== --- branches/0.3/src/codegen-ia32.cc (original) +++ branches/0.3/src/codegen-ia32.cc Tue Oct 28 01:56:02 2008 @@ -2839,38 +2839,26 @@ __ sar(ebx, kSmiTagSize); __ bind(&try_again_with_new_string); - // Get the type of the heap object into ecx. + // Get the type of the heap object into edi. __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); + __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset)); // We don't handle non-strings. - __ test(ecx, Immediate(kIsNotStringMask)); + __ test(edi, Immediate(kIsNotStringMask)); __ j(not_zero, &slow_case, not_taken); + // Here we make assumptions about the tag values and the shifts needed. + // See the comment in objects.h. + ASSERT(kLongStringTag == 0); + ASSERT(kMediumStringTag + String::kLongLengthShift == + String::kMediumLengthShift); + ASSERT(kShortStringTag + String::kLongLengthShift == + String::kShortLengthShift); + __ mov(ecx, Operand(edi)); + __ and_(ecx, kStringSizeMask); + __ add(Operand(ecx), Immediate(String::kLongLengthShift)); // Get the length field. __ mov(edx, FieldOperand(eax, String::kLengthOffset)); - Label long_string; - Label medium_string; - Label string_length_shifted; - // The code assumes the tags are disjoint. - ASSERT((kLongStringTag & kMediumStringTag) == 0); - ASSERT(kShortStringTag == 0); - __ test(ecx, Immediate(kLongStringTag)); - __ j(not_zero, &long_string, not_taken); - __ test(ecx, Immediate(kMediumStringTag)); - __ j(not_zero, &medium_string, taken); - // Short string. - __ shr(edx, String::kShortLengthShift); - __ jmp(&string_length_shifted); - - // Medium string. - __ bind(&medium_string); - __ shr(edx, String::kMediumLengthShift - String::kLongLengthShift); - // Fall through to long string. - __ bind(&long_string); - __ shr(edx, String::kLongLengthShift); - - __ bind(&string_length_shifted); - ASSERT(kSmiTag == 0); + __ shr(edx); // ecx is implicit operand. // edx is now the length of the string. // Check for index out of range. @@ -2879,11 +2867,11 @@ // We need special handling for non-flat strings. ASSERT(kSeqStringTag == 0); - __ test(ecx, Immediate(kStringRepresentationMask)); + __ test(edi, Immediate(kStringRepresentationMask)); __ j(not_zero, ¬_a_flat_string, not_taken); // Check for 1-byte or 2-byte string. - __ test(ecx, Immediate(kStringEncodingMask)); + __ test(edi, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii_string, taken); // 2-byte string. @@ -2903,11 +2891,10 @@ frame_->Push(eax); __ jmp(&end); - // Handle non-flat strings. __ bind(¬_a_flat_string); - __ and_(ecx, kStringRepresentationMask); - __ cmp(ecx, kConsStringTag); + __ and_(edi, kStringRepresentationMask); + __ cmp(edi, kConsStringTag); __ j(not_equal, ¬_a_cons_string_either, not_taken); // ConsString. @@ -2916,7 +2903,7 @@ __ jmp(&try_again_with_new_string); __ bind(¬_a_cons_string_either); - __ cmp(ecx, kSlicedStringTag); + __ cmp(edi, kSlicedStringTag); __ j(not_equal, &slow_case, not_taken); // SlicedString. Modified: branches/0.3/src/execution.cc ============================================================================== --- branches/0.3/src/execution.cc (original) +++ branches/0.3/src/execution.cc Tue Oct 28 01:56:02 2008 @@ -91,10 +91,12 @@ value->Verify(); #endif - // Update the pending exception and external caught flag and return the value. + // Update the pending exception flag and return the value. *has_pending_exception = value->IsException(); ASSERT(*has_pending_exception == Top::has_pending_exception()); - Top::propagate_external_caught(); + if (*has_pending_exception) { + Top::setup_external_caught(); + } // If the pending exception is OutOfMemoryException set out_of_memory in // the global context. Note: We have to mark the global context here Modified: branches/0.3/src/ic-arm.cc ============================================================================== --- branches/0.3/src/ic-arm.cc (original) +++ branches/0.3/src/ic-arm.cc Tue Oct 28 01:56:02 2008 @@ -156,103 +156,61 @@ } -void LoadIC::GenerateShortStringLength(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // -- [sp] : receiver - // ----------------------------------- - - Label miss; - - __ ldr(r0, MemOperand(sp, 0)); - +// Generate code to check if an object is a string. If the object is +// a string, the map's instance type is left in the scratch1 register. +static void GenerateStringCheck(MacroAssembler* masm, + Register receiver, + Register scratch1, + Register scratch2, + Label* smi, + Label* non_string_object) { // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, smi); - // Check that the object is a short string. - __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask)); + // Check that the object is a string. + __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); + __ and_(scratch2, scratch1, Operand(kIsNotStringMask)); // The cast is to resolve the overload for the argument of 0x0. - __ cmp(r1, Operand(static_cast<int32_t>(kStringTag | kShortStringTag))); - __ b(ne, &miss); - - // Load length directly from the string. - __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset)); - __ mov(r0, Operand(r0, LSR, String::kShortLengthShift)); - __ mov(r0, Operand(r0, LSL, kSmiTagSize)); - __ Ret(); - - // Cache miss: Jump to runtime. - __ bind(&miss); - Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag))); + __ b(ne, non_string_object); } -void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) { +void LoadIC::GenerateStringLength(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address // -- [sp] : receiver // ----------------------------------- - Label miss; + Label miss, load_length, check_wrapper; __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - - // Check that the object is a medium string. - __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask)); - __ cmp(r1, Operand(kStringTag | kMediumStringTag)); - __ b(ne, &miss); + // Check if the object is a string. + GenerateStringCheck(masm, r0, r1, r3, &miss, &check_wrapper); // Load length directly from the string. + __ bind(&load_length); + __ and_(r1, r1, Operand(kStringSizeMask)); + __ add(r1, r1, Operand(String::kHashShift)); __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset)); - __ mov(r0, Operand(r0, LSR, String::kMediumLengthShift)); + __ mov(r0, Operand(r0, LSR, r1)); __ mov(r0, Operand(r0, LSL, kSmiTagSize)); __ Ret(); - // Cache miss: Jump to runtime. - __ bind(&miss); - Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); -} - - -void LoadIC::GenerateLongStringLength(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // -- [sp] : receiver - // ----------------------------------- - - Label miss; - - __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - - // Check that the object is a long string. - __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask)); - __ cmp(r1, Operand(kStringTag | kLongStringTag)); + // Check if the object is a JSValue wrapper. + __ bind(&check_wrapper); + __ cmp(r0, Operand(JS_VALUE_TYPE)); __ b(ne, &miss); - // Load length directly from the string. - __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset)); - __ mov(r0, Operand(r0, LSR, String::kLongLengthShift)); - __ mov(r0, Operand(r0, LSL, kSmiTagSize)); - __ Ret(); + // Check if the wrapped value is a string and load the length + // directly if it is. + __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); + GenerateStringCheck(masm, r0, r1, r3, &miss, &miss); + __ b(&load_length); // Cache miss: Jump to runtime. __ bind(&miss); Modified: branches/0.3/src/ic-ia32.cc ============================================================================== --- branches/0.3/src/ic-ia32.cc (original) +++ branches/0.3/src/ic-ia32.cc Tue Oct 28 01:56:02 2008 @@ -138,7 +138,7 @@ } -void LoadIC::GenerateShortStringLength(MacroAssembler* masm) { +void LoadIC::GenerateStringLength(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- ecx : name // -- esp[0] : return address @@ -149,41 +149,7 @@ __ mov(eax, Operand(esp, kPointerSize)); - StubCompiler::GenerateLoadShortStringLength(masm, eax, edx, &miss); - __ bind(&miss); - StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); -} - - -void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : name - // -- esp[0] : return address - // -- esp[4] : receiver - // ----------------------------------- - - Label miss; - - __ mov(eax, Operand(esp, kPointerSize)); - - StubCompiler::GenerateLoadMediumStringLength(masm, eax, edx, &miss); - __ bind(&miss); - StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); -} - - -void LoadIC::GenerateLongStringLength(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : name - // -- esp[0] : return address - // -- esp[4] : receiver - // ----------------------------------- - - Label miss; - - __ mov(eax, Operand(esp, kPointerSize)); - - StubCompiler::GenerateLoadLongStringLength(masm, eax, edx, &miss); + StubCompiler::GenerateLoadStringLength(masm, eax, edx, &miss); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } Modified: branches/0.3/src/ic.cc ============================================================================== --- branches/0.3/src/ic.cc (original) +++ branches/0.3/src/ic.cc Tue Oct 28 01:56:02 2008 @@ -453,20 +453,22 @@ } if (FLAG_use_ic) { - // Use specialized code for getting the length of strings. - if (object->IsString() && name->Equals(Heap::length_symbol())) { + // Use specialized code for getting the length of strings and + // string wrapper objects. The length property of string wrapper + // objects is read-only and therefore always returns the length of + // the underlying string value. See ECMA-262 15.5.5.1. + if ((object->IsString() || object->IsStringWrapper()) && + name->Equals(Heap::length_symbol())) { + HandleScope scope; + // Get the string if we have a string wrapper object. + if (object->IsJSValue()) { + object = Handle<Object>(Handle<JSValue>::cast(object)->value()); + } #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); #endif Code* target = NULL; - if (object->IsShortString()) { - target = Builtins::builtin(Builtins::LoadIC_ShortStringLength); - } else if (object->IsMediumString()) { - target = Builtins::builtin(Builtins::LoadIC_MediumStringLength); - } else { - ASSERT(object->IsLongString()); - target = Builtins::builtin(Builtins::LoadIC_LongStringLength); - } + target = Builtins::builtin(Builtins::LoadIC_StringLength); set_target(target); StubCache::Set(*name, HeapObject::cast(*object)->map(), target); return Smi::FromInt(String::cast(*object)->length()); @@ -637,15 +639,7 @@ if (object->IsString() && name->Equals(Heap::length_symbol())) { Handle<String> string = Handle<String>::cast(object); Object* code = NULL; - if (string->IsShortString()) { - code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); - } else if (string->IsMediumString()) { - code = - StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); - } else { - ASSERT(string->IsLongString()); - code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); - } + code = StubCache::ComputeKeyedLoadStringLength(*name, *string); if (code->IsFailure()) return code; set_target(Code::cast(code)); #ifdef DEBUG Modified: branches/0.3/src/ic.h ============================================================================== --- branches/0.3/src/ic.h (original) +++ branches/0.3/src/ic.h Tue Oct 28 01:56:02 2008 @@ -211,9 +211,7 @@ // Specialized code generator routines. static void GenerateArrayLength(MacroAssembler* masm); - static void GenerateShortStringLength(MacroAssembler* masm); - static void GenerateMediumStringLength(MacroAssembler* masm); - static void GenerateLongStringLength(MacroAssembler* masm); + static void GenerateStringLength(MacroAssembler* masm); static void GenerateFunctionPrototype(MacroAssembler* masm); private: Modified: branches/0.3/src/jsregexp.cc ============================================================================== --- branches/0.3/src/jsregexp.cc (original) +++ branches/0.3/src/jsregexp.cc Tue Oct 28 01:56:02 2008 @@ -30,11 +30,20 @@ #include "execution.h" #include "factory.h" #include "jsregexp.h" -#include "third_party/jscre/pcre.h" #include "platform.h" #include "runtime.h" #include "top.h" #include "compilation-cache.h" + +// Including pcre.h undefines DEBUG to avoid getting debug output from +// the JSCRE implementation. Make sure to redefine it in debug mode +// after having included the header file. +#ifdef DEBUG +#include "third_party/jscre/pcre.h" +#define DEBUG +#else +#include "third_party/jscre/pcre.h" +#endif namespace v8 { namespace internal { Modified: branches/0.3/src/objects-inl.h ============================================================================== --- branches/0.3/src/objects-inl.h (original) +++ branches/0.3/src/objects-inl.h Tue Oct 28 01:56:02 2008 @@ -301,6 +301,11 @@ } +bool Object::IsStringWrapper() { + return IsJSValue() && JSValue::cast(this)->value()->IsString(); +} + + bool Object::IsProxy() { return Object::IsHeapObject() && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; @@ -1261,36 +1266,22 @@ int String::length() { uint32_t len = READ_INT_FIELD(this, kLengthOffset); - switch (size_tag()) { - case kShortStringTag: - return len >> kShortLengthShift; - case kMediumStringTag: - return len >> kMediumLengthShift; - case kLongStringTag: - return len >> kLongLengthShift; - default: - break; - } - UNREACHABLE(); - return 0; + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + return len >> (size_tag() + kLongLengthShift); } void String::set_length(int value) { - switch (size_tag()) { - case kShortStringTag: - WRITE_INT_FIELD(this, kLengthOffset, value << kShortLengthShift); - break; - case kMediumStringTag: - WRITE_INT_FIELD(this, kLengthOffset, value << kMediumLengthShift); - break; - case kLongStringTag: - WRITE_INT_FIELD(this, kLengthOffset, value << kLongLengthShift); - break; - default: - UNREACHABLE(); - break; - } + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + + WRITE_INT_FIELD(this, + kLengthOffset, + value << (size_tag() + kLongLengthShift)); } @@ -1474,21 +1465,14 @@ int SeqTwoByteString::SeqTwoByteStringSize(Map* map) { uint32_t length = READ_INT_FIELD(this, kLengthOffset); + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + // Use the map (and not 'this') to compute the size tag, since // TwoByteStringSize is called during GC when maps are encoded. - switch (map_size_tag(map)) { - case kShortStringTag: - length = length >> kShortLengthShift; - break; - case kMediumStringTag: - length = length >> kMediumLengthShift; - break; - case kLongStringTag: - length = length >> kLongLengthShift; - break; - default: - break; - } + length >>= map_size_tag(map) + kLongLengthShift; + return SizeFor(length); } @@ -1496,21 +1480,13 @@ int SeqAsciiString::SeqAsciiStringSize(Map* map) { uint32_t length = READ_INT_FIELD(this, kLengthOffset); + ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift); + ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift); + ASSERT(kLongStringTag == 0); + // Use the map (and not 'this') to compute the size tag, since // AsciiStringSize is called during GC when maps are encoded. - switch (map_size_tag(map)) { - case kShortStringTag: - length = length >> kShortLengthShift; - break; - case kMediumStringTag: - length = length >> kMediumLengthShift; - break; - case kLongStringTag: - length = length >> kLongLengthShift; - break; - default: - break; - } + length >>= map_size_tag(map) + kLongLengthShift; return SizeFor(length); } Modified: branches/0.3/src/objects.cc ============================================================================== --- branches/0.3/src/objects.cc (original) +++ branches/0.3/src/objects.cc Tue Oct 28 01:56:02 2008 @@ -3912,10 +3912,12 @@ } else { payload = v8::internal::HashField(GetHash(), false); } - return (payload & 0x00FFFFFF) | (length_ << String::kShortLengthShift); + return (payload & ((1 << String::kShortLengthShift) - 1)) | + (length_ << String::kShortLengthShift); } else if (length_ <= String::kMaxMediumStringSize) { uint32_t payload = v8::internal::HashField(GetHash(), false); - return (payload & 0x0000FFFF) | (length_ << String::kMediumLengthShift); + return (payload & ((1 << String::kMediumLengthShift) - 1)) | + (length_ << String::kMediumLengthShift); } else { return v8::internal::HashField(length_, false); } Modified: branches/0.3/src/objects.h ============================================================================== --- branches/0.3/src/objects.h (original) +++ branches/0.3/src/objects.h Tue Oct 28 01:56:02 2008 @@ -393,29 +393,30 @@ const uint32_t kStringTag = 0x0; const uint32_t kNotStringTag = 0x80; -// If bit 7 is clear, bits 5 and 6 are the string's size (short, medium, or -// long). -const uint32_t kStringSizeMask = 0x60; -const uint32_t kShortStringTag = 0x0; -const uint32_t kMediumStringTag = 0x20; -const uint32_t kLongStringTag = 0x40; - -// If bit 7 is clear, bit 4 indicates that the string is a symbol (if set) or +// If bit 7 is clear, bit 5 indicates that the string is a symbol (if set) or // not (if cleared). -const uint32_t kIsSymbolMask = 0x10; +const uint32_t kIsSymbolMask = 0x20; const uint32_t kNotSymbolTag = 0x0; -const uint32_t kSymbolTag = 0x10; +const uint32_t kSymbolTag = 0x20; -// If bit 7 is clear, and the string representation is a sequential string, -// then bit 3 indicates whether the string consists of two-byte characters or -// one-byte characters. -const uint32_t kStringEncodingMask = 0x8; +// If bit 7 is clear, bits 3 and 4 are the string's size (short, medium or +// long). These values are very special in that they are also used to shift +// the length field to get the length, removing the hash value. This avoids +// using if or switch when getting the length of a string. +const uint32_t kStringSizeMask = 0x18; +const uint32_t kShortStringTag = 0x18; +const uint32_t kMediumStringTag = 0x10; +const uint32_t kLongStringTag = 0x00; + +// If bit 7 is clear then bit 2 indicates whether the string consists of +// two-byte characters or one-byte characters. +const uint32_t kStringEncodingMask = 0x4; const uint32_t kTwoByteStringTag = 0x0; -const uint32_t kAsciiStringTag = 0x8; +const uint32_t kAsciiStringTag = 0x4; -// If bit 7 is clear, the low-order 3 bits indicate the representation +// If bit 7 is clear, the low-order 2 bits indicate the representation // of the string. -const uint32_t kStringRepresentationMask = 0x07; +const uint32_t kStringRepresentationMask = 0x03; enum StringRepresentationTag { kSeqStringTag = 0x0, kConsStringTag = 0x1, @@ -622,6 +623,7 @@ inline bool IsOddball(); inline bool IsSharedFunctionInfo(); inline bool IsJSValue(); + inline bool IsStringWrapper(); inline bool IsProxy(); inline bool IsBoolean(); inline bool IsJSArray(); @@ -3116,8 +3118,8 @@ static const int kSize = kLengthOffset + kIntSize; // Limits on sizes of different types of strings. - static const int kMaxShortStringSize = 255; - static const int kMaxMediumStringSize = 65535; + static const int kMaxShortStringSize = 63; + static const int kMaxMediumStringSize = 16383; static const int kMaxArrayIndexSize = 10; @@ -3138,14 +3140,14 @@ // Array index strings this short can keep their index in the hash // field. - static const int kMaxCachedArrayIndexLength = 6; + static const int kMaxCachedArrayIndexLength = 7; // Shift constants for retriving length and hash code from // length/hash field. static const int kHashShift = kNofLengthBitFields; - static const int kShortLengthShift = 3 * kBitsPerByte; - static const int kMediumLengthShift = 2 * kBitsPerByte; - static const int kLongLengthShift = kHashShift; + static const int kShortLengthShift = kHashShift + kShortStringTag; + static const int kMediumLengthShift = kHashShift + kMediumStringTag; + static const int kLongLengthShift = kHashShift + kLongStringTag; // Limit for truncation in short printing. static const int kMaxShortPrintLength = 1024; Modified: branches/0.3/src/runtime.js ============================================================================== --- branches/0.3/src/runtime.js (original) +++ branches/0.3/src/runtime.js Tue Oct 28 01:56:02 2008 @@ -78,12 +78,15 @@ // NOTE: This checks for both null and undefined. return (y == null) ? 0 : 1; } else { + // x is not a number, boolean, null or undefined. + if (y == null) return 1; // not equal if (IS_OBJECT(y)) { return %_ObjectEquals(x, y) ? 0 : 1; } if (IS_FUNCTION(y)) { return %_ObjectEquals(x, y) ? 0 : 1; } + x = %ToPrimitive(x, NO_HINT); } } Modified: branches/0.3/src/stub-cache-arm.cc ============================================================================== --- branches/0.3/src/stub-cache-arm.cc (original) +++ branches/0.3/src/stub-cache-arm.cc Tue Oct 28 01:56:02 2008 @@ -800,19 +800,7 @@ } -Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); -} - - -Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); -} - - -Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) { +Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { UNIMPLEMENTED(); return Heap::undefined_value(); } Modified: branches/0.3/src/stub-cache-ia32.cc ============================================================================== --- branches/0.3/src/stub-cache-ia32.cc (original) +++ branches/0.3/src/stub-cache-ia32.cc Tue Oct 28 01:56:02 2008 @@ -159,71 +159,55 @@ } -void StubCompiler::GenerateLoadShortStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label) { - // Check that the receiver isn't a smi. - __ test(receiver, Immediate(kSmiTagMask)); - __ j(zero, miss_label, not_taken); - - // Check that the object is a short string. - __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); - __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - __ and_(scratch, kIsNotStringMask | kStringSizeMask); - __ cmp(scratch, kStringTag | kShortStringTag); - __ j(not_equal, miss_label, not_taken); - - // Load length directly from the string. - __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); - __ shr(eax, String::kShortLengthShift); - __ shl(eax, kSmiTagSize); - __ ret(0); -} - -void StubCompiler::GenerateLoadMediumStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label) { - // Check that the receiver isn't a smi. +// Generate code to check if an object is a string. If the object is +// a string, the map's instance type is left in the scratch register. +static void GenerateStringCheck(MacroAssembler* masm, + Register receiver, + Register scratch, + Label* smi, + Label* non_string_object) { + // Check that the object isn't a smi. __ test(receiver, Immediate(kSmiTagMask)); - __ j(zero, miss_label, not_taken); + __ j(zero, smi, not_taken); - // Check that the object is a short string. + // Check that the object is a string. __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - __ and_(scratch, kIsNotStringMask | kStringSizeMask); - __ cmp(scratch, kStringTag | kMediumStringTag); - __ j(not_equal, miss_label, not_taken); - - // Load length directly from the string. - __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); - __ shr(eax, String::kMediumLengthShift); - __ shl(eax, kSmiTagSize); - __ ret(0); + ASSERT(kNotStringTag != 0); + __ test(scratch, Immediate(kNotStringTag)); + __ j(not_zero, non_string_object, not_taken); } -void StubCompiler::GenerateLoadLongStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label) { - // Check that the receiver isn't a smi. - __ test(receiver, Immediate(kSmiTagMask)); - __ j(zero, miss_label, not_taken); +void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, + Register receiver, + Register scratch, + Label* miss) { + Label load_length, check_wrapper; - // Check that the object is a short string. - __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); - __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - __ and_(scratch, kIsNotStringMask | kStringSizeMask); - __ cmp(scratch, kStringTag | kLongStringTag); - __ j(not_equal, miss_label, not_taken); + // Check if the object is a string. + GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper); // Load length directly from the string. + __ bind(&load_length); + __ and_(scratch, kStringSizeMask); __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); - __ shr(eax, String::kLongLengthShift); + // ecx is also the receiver. + __ lea(ecx, Operand(scratch, String::kLongLengthShift)); + __ shr(eax); // ecx is implicit shift register. __ shl(eax, kSmiTagSize); __ ret(0); + + // Check if the object is a JSValue wrapper. + __ bind(&check_wrapper); + __ cmp(receiver, JS_VALUE_TYPE); + __ j(not_equal, miss, not_taken); + + // Check if the wrapped value is a string and load the length + // directly if it is. + __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset)); + GenerateStringCheck(masm, receiver, scratch, miss, miss); + __ jmp(&load_length); } @@ -1140,61 +1124,7 @@ } -Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver - // ----------------------------------- - HandleScope scope; - Label miss; - - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); - __ IncrementCounter(&Counters::keyed_load_string_length, 1); - - // Check that the name has not changed. - __ cmp(Operand(eax), Immediate(Handle<String>(name))); - __ j(not_equal, &miss, not_taken); - - GenerateLoadShortStringLength(masm(), ecx, edx, &miss); - __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_string_length, 1); - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - - // Return the generated code. - return GetCode(CALLBACKS); -} - - -Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // -- esp[4] : name - // -- esp[8] : receiver - // ----------------------------------- - HandleScope scope; - Label miss; - - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); - __ IncrementCounter(&Counters::keyed_load_string_length, 1); - - // Check that the name has not changed. - __ cmp(Operand(eax), Immediate(Handle<String>(name))); - __ j(not_equal, &miss, not_taken); - - GenerateLoadMediumStringLength(masm(), ecx, edx, &miss); - __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_string_length, 1); - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - - // Return the generated code. - return GetCode(CALLBACKS); -} - - -Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) { +Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { // ----------- S t a t e ------------- // -- esp[0] : return address // -- esp[4] : name @@ -1211,7 +1141,7 @@ __ cmp(Operand(eax), Immediate(Handle<String>(name))); __ j(not_equal, &miss, not_taken); - GenerateLoadLongStringLength(masm(), ecx, edx, &miss); + GenerateLoadStringLength(masm(), ecx, edx, &miss); __ bind(&miss); __ DecrementCounter(&Counters::keyed_load_string_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); Modified: branches/0.3/src/stub-cache.cc ============================================================================== --- branches/0.3/src/stub-cache.cc (original) +++ branches/0.3/src/stub-cache.cc Tue Oct 28 01:56:02 2008 @@ -263,48 +263,14 @@ } -Object* StubCache::ComputeKeyedLoadShortStringLength(String* name, - String* receiver) { +Object* StubCache::ComputeKeyedLoadStringLength(String* name, + String* receiver) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { KeyedLoadStubCompiler compiler; - code = compiler.CompileLoadShortStringLength(name); - if (code->IsFailure()) return code; - LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name)); - Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); - if (result->IsFailure()) return result; - } - return code; -} - - -Object* StubCache::ComputeKeyedLoadMediumStringLength(String* name, - String* receiver) { - Code::Flags flags = - Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); - Object* code = receiver->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - KeyedLoadStubCompiler compiler; - code = compiler.CompileLoadMediumStringLength(name); - if (code->IsFailure()) return code; - LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name)); - Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); - if (result->IsFailure()) return result; - } - return code; -} - - -Object* StubCache::ComputeKeyedLoadLongStringLength(String* name, - String* receiver) { - Code::Flags flags = - Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS); - Object* code = receiver->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - KeyedLoadStubCompiler compiler; - code = compiler.CompileLoadLongStringLength(name); + code = compiler.CompileLoadStringLength(name); if (code->IsFailure()) return code; LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name)); Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); Modified: branches/0.3/src/stub-cache.h ============================================================================== --- branches/0.3/src/stub-cache.h (original) +++ branches/0.3/src/stub-cache.h Tue Oct 28 01:56:02 2008 @@ -98,14 +98,8 @@ static Object* ComputeKeyedLoadArrayLength(String* name, JSArray* receiver); - static Object* ComputeKeyedLoadShortStringLength(String* name, - String* receiver); - - static Object* ComputeKeyedLoadMediumStringLength(String* name, - String* receiver); - - static Object* ComputeKeyedLoadLongStringLength(String* name, - String* receiver); + static Object* ComputeKeyedLoadStringLength(String* name, + String* receiver); static Object* ComputeKeyedLoadFunctionPrototype(String* name, JSFunction* receiver); @@ -341,18 +335,10 @@ Register receiver, Register scratch, Label* miss_label); - static void GenerateLoadShortStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label); - static void GenerateLoadMediumStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label); - static void GenerateLoadLongStringLength(MacroAssembler* masm, - Register receiver, - Register scratch, - Label* miss_label); + static void GenerateLoadStringLength(MacroAssembler* masm, + Register receiver, + Register scratch, + Label* miss_label); static void GenerateLoadFunctionPrototype(MacroAssembler* masm, Register receiver, Register scratch1, @@ -415,9 +401,7 @@ JSObject* holder, String* name); Object* CompileLoadArrayLength(String* name); - Object* CompileLoadShortStringLength(String* name); - Object* CompileLoadMediumStringLength(String* name); - Object* CompileLoadLongStringLength(String* name); + Object* CompileLoadStringLength(String* name); Object* CompileLoadFunctionPrototype(String* name); private: Modified: branches/0.3/src/top.cc ============================================================================== --- branches/0.3/src/top.cc (original) +++ branches/0.3/src/top.cc Tue Oct 28 01:56:02 2008 @@ -103,7 +103,7 @@ clear_pending_exception(); clear_scheduled_exception(); thread_local_.save_context_ = NULL; - thread_local_.pending_external_caught_exception_ = false; + thread_local_.catcher_ = NULL; } @@ -595,7 +595,7 @@ Failure* Top::ReThrow(Object* exception, MessageLocation* location) { - // Set the exception being re-thrown. + // Set the exception beeing re-thrown. set_pending_exception(exception); return Failure::Exception(); } @@ -777,8 +777,9 @@ // If the exception is caught externally, we store it in the // try/catch handler. The C code can find it later and process it if // necessary. - thread_local_.pending_external_caught_exception_ = is_caught_externally; + thread_local_.catcher_ = NULL; if (is_caught_externally) { + thread_local_.catcher_ = thread_local_.try_catch_handler_; thread_local_.try_catch_handler_->exception_ = reinterpret_cast<void*>(*exception_handle); if (!message_obj.is_null()) { @@ -793,7 +794,7 @@ if (report_exception) { if (message != NULL) { MessageHandler::ReportMessage(message); - } else { + } else if (!message_obj.is_null()) { MessageHandler::ReportMessage(location, message_obj); } } Modified: branches/0.3/src/top.h ============================================================================== --- branches/0.3/src/top.h (original) +++ branches/0.3/src/top.h Tue Oct 28 01:56:02 2008 @@ -54,9 +54,7 @@ bool external_caught_exception_; v8::TryCatch* try_catch_handler_; SaveContext* save_context_; - // Flag indicating that the try_catch_handler_ contains an exception to be - // caught. - bool pending_external_caught_exception_; + v8::TryCatch* catcher_; // Stack. Address c_entry_fp_; // the frame pointer of the top c entry frame @@ -160,16 +158,10 @@ thread_local_.scheduled_exception_ = Heap::the_hole_value(); } - // Propagate the external caught exception flag. If there is no external - // caught exception always clear the TryCatch handler as it might contain - // an exception object from a throw which was bypassed by a finally block - // doing an explicit return/break/continue. - static void propagate_external_caught() { - if (has_pending_exception()) { - thread_local_.external_caught_exception_ = - thread_local_.pending_external_caught_exception_; - } - thread_local_.pending_external_caught_exception_ = false; + static void setup_external_caught() { + thread_local_.external_caught_exception_ = + (thread_local_.catcher_ != NULL) && + (Top::thread_local_.try_catch_handler_ == Top::thread_local_.catcher_); } // Tells whether the current context has experienced an out of memory Modified: branches/0.3/test/mjsunit/mjsunit.status ============================================================================== --- branches/0.3/test/mjsunit/mjsunit.status (original) +++ branches/0.3/test/mjsunit/mjsunit.status Tue Oct 28 01:56:02 2008 @@ -61,3 +61,7 @@ debug-breakpoints: PASS || FAIL regress/regress-998565: FAIL + +# Bug number 130 http://code.google.com/p/v8/issues/detail?id=130 +# Fails on real ARM hardware but not on the simulator. +string-compare-alignment: PASS || FAIL --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list v8-dev@googlegroups.com http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---