Revision: 3339 Author: [email protected] Date: Fri Nov 20 04:14:52 2009 Log: Push version 2.0.1 to trunk.
Fixed crash bug in String.prototype.replace. Reverted a change which caused Chromium interactive ui test failures. http://code.google.com/p/v8/source/detail?r=3339 Added: /trunk/test/mjsunit/regress/regress-515.js Modified: /trunk/ChangeLog /trunk/src/arm/codegen-arm.cc /trunk/src/arm/codegen-arm.h /trunk/src/codegen.cc /trunk/src/compiler.cc /trunk/src/heap.cc /trunk/src/heap.h /trunk/src/ia32/codegen-ia32.cc /trunk/src/ia32/codegen-ia32.h /trunk/src/macros.py /trunk/src/objects-inl.h /trunk/src/objects.cc /trunk/src/objects.h /trunk/src/runtime.cc /trunk/src/version.cc /trunk/src/x64/codegen-x64.cc /trunk/src/x64/codegen-x64.h ======================================= --- /dev/null +++ /trunk/test/mjsunit/regress/regress-515.js Fri Nov 20 04:14:52 2009 @@ -0,0 +1,40 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Regression test for http://code.google.com/p/v8/issues/detail?id=515. +// +// The test passes if it does not crash. + +var length = 2048; +var s = ""; +for (var i = 0; i < 2048; i++) { + s += '.'; +} + +var string = s + 'x' + s + 'x' + s; + +string.replace(/x/g, "") ======================================= --- /trunk/ChangeLog Wed Nov 18 06:12:51 2009 +++ /trunk/ChangeLog Fri Nov 20 04:14:52 2009 @@ -1,3 +1,11 @@ +2009-11-20: Version 2.0.1 + + Fixed crash bug in String.prototype.replace. + + Reverted a change which caused Chromium interactive ui test + failures. + + 2009-11-18: Version 2.0.0 Added support for VFP on ARM. ======================================= --- /trunk/src/arm/codegen-arm.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/arm/codegen-arm.cc Fri Nov 20 04:14:52 2009 @@ -3383,6 +3383,51 @@ answer.Bind(); cc_reg_ = eq; } + + +void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') + VirtualFrame::SpilledScope spilled_scope; + ASSERT(args->length() == 1); + LoadAndSpill(args->at(0)); + frame_->EmitPop(r1); + __ tst(r1, Operand(kSmiTagMask)); + false_target()->Branch(eq); + + __ LoadRoot(ip, Heap::kNullValueRootIndex); + __ cmp(r1, ip); + true_target()->Branch(eq); + + Register map_reg = r2; + __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset)); + // Undetectable objects behave like undefined when tested with typeof. + __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset)); + __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); + __ cmp(r1, Operand(1 << Map::kIsUndetectable)); + false_target()->Branch(eq); + + __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); + __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); + false_target()->Branch(lt); + __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); + cc_reg_ = le; +} + + +void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (%_ClassOf(arg) === 'Function') + VirtualFrame::SpilledScope spilled_scope; + ASSERT(args->length() == 1); + LoadAndSpill(args->at(0)); + frame_->EmitPop(r0); + __ tst(r0, Operand(kSmiTagMask)); + false_target()->Branch(eq); + Register map_reg = r2; + __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE); + cc_reg_ = eq; +} void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { ======================================= --- /trunk/src/arm/codegen-arm.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/arm/codegen-arm.h Fri Nov 20 04:14:52 2009 @@ -334,6 +334,8 @@ void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsObject(ZoneList<Expression*>* args); + void GenerateIsFunction(ZoneList<Expression*>* args); // Support for construct call checks. void GenerateIsConstructCall(ZoneList<Expression*>* args); ======================================= --- /trunk/src/codegen.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/codegen.cc Fri Nov 20 04:14:52 2009 @@ -343,7 +343,9 @@ {&CodeGenerator::GenerateLog, "_Log"}, {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"}, {&CodeGenerator::GenerateMathSin, "_Math_sin"}, - {&CodeGenerator::GenerateMathCos, "_Math_cos"} + {&CodeGenerator::GenerateMathCos, "_Math_cos"}, + {&CodeGenerator::GenerateIsObject, "_IsObject"}, + {&CodeGenerator::GenerateIsFunction, "_IsFunction"}, }; ======================================= --- /trunk/src/compiler.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/compiler.cc Fri Nov 20 04:14:52 2009 @@ -646,8 +646,9 @@ void CodeGenSelector::VisitDeclaration(Declaration* decl) { - if (decl->fun() != NULL) { - ProcessExpression(decl->fun(), Expression::kValue); + Variable* var = decl->proxy()->var(); + if (!var->is_global() || var->mode() == Variable::CONST) { + BAILOUT("Non-global declaration"); } } ======================================= --- /trunk/src/heap.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/heap.cc Fri Nov 20 04:14:52 2009 @@ -1760,6 +1760,41 @@ share->set_this_property_assignments(undefined_value()); return result; } + + +// Returns true for a character in a range. Both limits are inclusive. +static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { + // This makes uses of the the unsigned wraparound. + return character - from <= to - from; +} + + +static inline Object* MakeOrFindTwoCharacterString(uint32_t c1, uint32_t c2) { + String* symbol; + // Numeric strings have a different hash algorithm not known by + // LookupTwoCharsSymbolIfExists, so we skip this step for such strings. + if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && + Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) { + return symbol; + // Now we know the length is 2, we might as well make use of that fact + // when building the new string. + } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this + ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this. + Object* result = Heap::AllocateRawAsciiString(2); + if (result->IsFailure()) return result; + char* dest = SeqAsciiString::cast(result)->GetChars(); + dest[0] = c1; + dest[1] = c2; + return result; + } else { + Object* result = Heap::AllocateRawTwoByteString(2); + if (result->IsFailure()) return result; + uc16* dest = SeqTwoByteString::cast(result)->GetChars(); + dest[0] = c1; + dest[1] = c2; + return result; + } +} Object* Heap::AllocateConsString(String* first, String* second) { @@ -1774,6 +1809,16 @@ } 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(c1, c2); + } + bool is_ascii = first->IsAsciiRepresentation() && second->IsAsciiRepresentation(); @@ -1843,6 +1888,13 @@ if (length == 1) { return Heap::LookupSingleCharacterStringFromCode( buffer->Get(start)); + } else if (length == 2) { + // 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. + unsigned c1 = buffer->Get(start); + unsigned c2 = buffer->Get(start + 1); + return MakeOrFindTwoCharacterString(c1, c2); } // Make an attempt to flatten the buffer to reduce access time. ======================================= --- /trunk/src/heap.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/heap.h Fri Nov 20 04:14:52 2009 @@ -631,6 +631,7 @@ } static Object* LookupSymbol(String* str); static bool LookupSymbolIfExists(String* str, String** symbol); + static bool LookupTwoCharsSymbolIfExists(String* str, String** symbol); // Compute the matching symbol map for a string if possible. // NULL is returned if string is in new space or not flattened. ======================================= --- /trunk/src/ia32/codegen-ia32.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/ia32/codegen-ia32.cc Fri Nov 20 04:14:52 2009 @@ -4868,6 +4868,55 @@ temp.Unuse(); destination()->Split(equal); } + + +void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') + ASSERT(args->length() == 1); + Load(args->at(0)); + Result obj = frame_->Pop(); + obj.ToRegister(); + + __ test(obj.reg(), Immediate(kSmiTagMask)); + destination()->false_target()->Branch(zero); + __ cmp(obj.reg(), Factory::null_value()); + destination()->true_target()->Branch(equal); + + Result map = allocator()->Allocate(); + ASSERT(map.is_valid()); + __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); + // Undetectable objects behave like undefined when tested with typeof. + __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); + __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); + destination()->false_target()->Branch(not_zero); + __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); + __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); + __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE); + destination()->false_target()->Branch(less); + __ cmp(map.reg(), LAST_JS_OBJECT_TYPE); + obj.Unuse(); + map.Unuse(); + destination()->Split(less_equal); +} + + +void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (%_ClassOf(arg) === 'Function') + ASSERT(args->length() == 1); + Load(args->at(0)); + Result obj = frame_->Pop(); + obj.ToRegister(); + __ test(obj.reg(), Immediate(kSmiTagMask)); + destination()->false_target()->Branch(zero); + Result temp = allocator()->Allocate(); + ASSERT(temp.is_valid()); + __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, temp.reg()); + obj.Unuse(); + temp.Unuse(); + destination()->Split(equal); +} void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { ======================================= --- /trunk/src/ia32/codegen-ia32.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/ia32/codegen-ia32.h Fri Nov 20 04:14:52 2009 @@ -512,6 +512,8 @@ void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsObject(ZoneList<Expression*>* args); + void GenerateIsFunction(ZoneList<Expression*>* args); // Support for construct call checks. void GenerateIsConstructCall(ZoneList<Expression*>* args); ======================================= --- /trunk/src/macros.py Wed Nov 18 06:12:51 2009 +++ /trunk/src/macros.py Fri Nov 20 04:14:52 2009 @@ -79,11 +79,10 @@ macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined'); macro IS_NUMBER(arg) = (typeof(arg) === 'number'); macro IS_STRING(arg) = (typeof(arg) === 'string'); -macro IS_OBJECT(arg) = (typeof(arg) === 'object' | | %_ClassOf(arg) == 'RegExp'); macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); +macro IS_OBJECT(arg) = (%_IsObject(arg)); macro IS_ARRAY(arg) = (%_IsArray(arg)); -# IS_FUNCTION uses %_ClassOf rather than typeof so as to exclude regexps. -macro IS_FUNCTION(arg) = (%_ClassOf(arg) === 'Function'); +macro IS_FUNCTION(arg) = (%_IsFunction(arg)); macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); ======================================= --- /trunk/src/objects-inl.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/objects-inl.h Fri Nov 20 04:14:52 2009 @@ -3103,8 +3103,19 @@ void JSArray::EnsureSize(int required_size) { ASSERT(HasFastElements()); - if (elements()->length() >= required_size) return; - Expand(required_size); + Array* elts = elements(); + const int kArraySizeThatFitsComfortablyInNewSpace = 128; + if (elts->length() < required_size) { + // Doubling in size would be overkill, but leave some slack to avoid + // constantly growing. + Expand(required_size + (required_size >> 3)); + // It's a performance benefit to keep a frequently used array in new-space. + } else if (!Heap::new_space()->Contains(elts) && + required_size < kArraySizeThatFitsComfortablyInNewSpace) { + // Expand will allocate a new backing store in new space even if the size + // we asked for isn't larger than what we had before. + Expand(required_size); + } } ======================================= --- /trunk/src/objects.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/objects.cc Fri Nov 20 04:14:52 2009 @@ -1463,8 +1463,8 @@ Object* JSObject::ReplaceSlowProperty(String* name, - Object* value, - PropertyAttributes attributes) { + Object* value, + PropertyAttributes attributes) { StringDictionary* dictionary = property_dictionary(); int old_index = dictionary->FindEntry(name); int new_enumeration_index = 0; // 0 means "Use the next available index." @@ -1477,6 +1477,7 @@ PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); return SetNormalizedProperty(name, value, new_details); } + Object* JSObject::ConvertDescriptorToFieldAndMapTransition( String* name, @@ -1868,6 +1869,14 @@ // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; + + // Optimization for 2-byte strings often used as keys in a decompression + // dictionary. We make these short keys into symbols to avoid constantly + // reallocating them. + if (!name->IsSymbol() && name->length() <= 2) { + Object* symbol_version = Heap::LookupSymbol(name); + if (!symbol_version->IsFailure()) name = String::cast(symbol_version); + } // Check access rights if needed. if (IsAccessCheckNeeded() @@ -5240,9 +5249,7 @@ Handle<JSArray> self(this); Handle<FixedArray> old_backing(FixedArray::cast(elements())); int old_size = old_backing->length(); - // Doubling in size would be overkill, but leave some slack to avoid - // constantly growing. - int new_size = required_size + (required_size >> 3); + int new_size = required_size > old_size ? required_size : old_size; Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size); // Can't use this any more now because we may have had a GC! for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); @@ -7325,6 +7332,67 @@ SymbolKey key(string); return LookupKey(&key, s); } + + +// This class is used for looking up two character strings in the symbol table. +// If we don't have a hit we don't want to waste much time so we unroll the +// string hash calculation loop here for speed. Doesn't work if the two +// characters form a decimal integer, since such strings have a different hash +// algorithm. +class TwoCharHashTableKey : public HashTableKey { + public: + TwoCharHashTableKey(uint32_t c1, uint32_t c2) + : c1_(c1), c2_(c2) { + // Char 1. + uint32_t hash = c1 + (c1 << 10); + hash ^= hash >> 6; + // Char 2. + hash += c2; + hash += hash << 10; + hash ^= hash >> 6; + // GetHash. + hash += hash << 3; + hash ^= hash >> 11; + hash += hash << 15; + if (hash == 0) hash = 27; +#ifdef DEBUG + StringHasher hasher(2); + hasher.AddCharacter(c1); + hasher.AddCharacter(c2); + // If this assert fails then we failed to reproduce the two-character + // version of the string hashing algorithm above. One reason could be + // that we were passed two digits as characters, since the hash + // algorithm is different in that case. + ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash)); +#endif + hash_ = hash; + } + + bool IsMatch(Object* o) { + if (!o->IsString()) return false; + String* other = String::cast(o); + if (other->length() != 2) return false; + if (other->Get(0) != c1_) return false; + return other->Get(1) == c2_; + } + + uint32_t Hash() { return hash_; } + uint32_t HashForObject(Object* key) { + if (!key->IsString()) return 0; + return String::cast(key)->Hash(); + } + + Object* AsObject() { + // The TwoCharHashTableKey is only used for looking in the symbol + // table, not for adding to it. + UNREACHABLE(); + return NULL; + } + private: + uint32_t c1_; + uint32_t c2_; + uint32_t hash_; +}; bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { @@ -7339,6 +7407,22 @@ return true; } } + + +bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1, + uint32_t c2, + String** symbol) { + TwoCharHashTableKey key(c1, c2); + int entry = FindEntry(&key); + if (entry == kNotFound) { + return false; + } else { + String* result = String::cast(KeyAt(entry)); + ASSERT(StringShape(result).IsSymbol()); + *symbol = result; + return true; + } +} Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { ======================================= --- /trunk/src/objects.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/objects.h Fri Nov 20 04:14:52 2009 @@ -2188,6 +2188,7 @@ // true if it is found, assigning the symbol to the given output // parameter. bool LookupSymbolIfExists(String* str, String** symbol); + bool LookupTwoCharsSymbolIfExists(uint32_t c1, uint32_t c2, String** symbol); // Casting. static inline SymbolTable* cast(Object* obj); @@ -3846,6 +3847,7 @@ bool is_array_index_; bool is_first_char_; bool is_valid_; + friend class TwoCharHashTableKey; }; ======================================= --- /trunk/src/runtime.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/runtime.cc Fri Nov 20 04:14:52 2009 @@ -1750,10 +1750,10 @@ // Index of end of last match. int prev = 0; - // Number of parts added by compiled replacement plus preceeding string - // and possibly suffix after last match. It is possible for compiled - // replacements to use two elements when encoded as two smis. - const int parts_added_per_loop = compiled_replacement.parts() * 2 + 2; + // Number of parts added by compiled replacement plus preceeding + // string and possibly suffix after last match. It is possible for + // all components to use two elements when encoded as two smis. + const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); bool matched = true; do { ASSERT(last_match_info_handle->HasFastElements()); @@ -2356,12 +2356,20 @@ ASSERT(args.length() == 3); CONVERT_CHECKED(String, value, args[0]); - CONVERT_DOUBLE_CHECKED(from_number, args[1]); - CONVERT_DOUBLE_CHECKED(to_number, args[2]); - - int start = FastD2I(from_number); - int end = FastD2I(to_number); - + Object* from = args[1]; + Object* to = args[2]; + int start, end; + // We have a fast integer-only case here to avoid a conversion to double in + // the common case where from and to are Smis. + if (from->IsSmi() && to->IsSmi()) { + start = Smi::cast(from)->value(); + end = Smi::cast(to)->value(); + } else { + CONVERT_DOUBLE_CHECKED(from_number, from); + CONVERT_DOUBLE_CHECKED(to_number, to); + start = FastD2I(from_number); + end = FastD2I(to_number); + } RUNTIME_ASSERT(end >= start); RUNTIME_ASSERT(start >= 0); RUNTIME_ASSERT(end <= value->length()); ======================================= --- /trunk/src/version.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/version.cc Fri Nov 20 04:14:52 2009 @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 #define MINOR_VERSION 0 -#define BUILD_NUMBER 0 +#define BUILD_NUMBER 1 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false ======================================= --- /trunk/src/x64/codegen-x64.cc Wed Nov 18 06:12:51 2009 +++ /trunk/src/x64/codegen-x64.cc Fri Nov 20 04:14:52 2009 @@ -3614,6 +3614,48 @@ value.Unuse(); destination()->Split(equal); } + + +void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') + ASSERT(args->length() == 1); + Load(args->at(0)); + Result obj = frame_->Pop(); + obj.ToRegister(); + Condition is_smi = masm_->CheckSmi(obj.reg()); + destination()->false_target()->Branch(is_smi); + + __ Move(kScratchRegister, Factory::null_value()); + __ cmpq(obj.reg(), kScratchRegister); + destination()->true_target()->Branch(equal); + + __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); + // Undetectable objects behave like undefined when tested with typeof. + __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), + Immediate(1 << Map::kIsUndetectable)); + destination()->false_target()->Branch(not_zero); + __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); + destination()->false_target()->Branch(less); + __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); + obj.Unuse(); + destination()->Split(less_equal); +} + + +void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { + // This generates a fast version of: + // (%_ClassOf(arg) === 'Function') + ASSERT(args->length() == 1); + Load(args->at(0)); + Result obj = frame_->Pop(); + obj.ToRegister(); + Condition is_smi = masm_->CheckSmi(obj.reg()); + destination()->false_target()->Branch(is_smi); + __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister); + obj.Unuse(); + destination()->Split(equal); +} void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { ======================================= --- /trunk/src/x64/codegen-x64.h Wed Nov 18 06:12:51 2009 +++ /trunk/src/x64/codegen-x64.h Fri Nov 20 04:14:52 2009 @@ -510,6 +510,8 @@ void GenerateIsSmi(ZoneList<Expression*>* args); void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); void GenerateIsArray(ZoneList<Expression*>* args); + void GenerateIsObject(ZoneList<Expression*>* args); + void GenerateIsFunction(ZoneList<Expression*>* args); // Support for construct call checks. void GenerateIsConstructCall(ZoneList<Expression*>* args); --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
