From a640707213d9952fe19d3e3e26be69e82869980c Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Fri, 11 Apr 2014 07:27:25 +0000 Subject: [PATCH] Implement handlified String::Equals and Name::Equals. R=ulan@chromium.org Review URL: https://codereview.chromium.org/225823003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20669 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/accessors.cc | 20 ++-- src/api.cc | 3 +- src/arm/full-codegen-arm.cc | 17 ++-- src/arm/lithium-codegen-arm.cc | 18 ++-- src/arm64/full-codegen-arm64.cc | 17 ++-- src/arm64/lithium-codegen-arm64.cc | 18 ++-- src/ast.cc | 8 +- src/ast.h | 2 +- src/compilation-cache.cc | 3 +- src/contexts.cc | 2 +- src/conversions.cc | 19 +++- src/conversions.h | 12 ++- src/factory.cc | 7 +- src/func-name-inferrer.cc | 6 +- src/heap-inl.h | 19 ---- src/heap.h | 9 -- src/hydrogen.h | 4 +- src/ia32/full-codegen-ia32.cc | 17 ++-- src/ia32/lithium-codegen-ia32.cc | 17 ++-- src/ic.cc | 11 ++- src/json-parser.h | 9 +- src/mips/full-codegen-mips.cc | 17 ++-- src/mips/lithium-codegen-mips.cc | 18 ++-- src/objects-inl.h | 36 ++++--- src/objects.cc | 147 +++++++++++---------------- src/objects.h | 59 +++++------ src/parser.cc | 15 +-- src/runtime.cc | 198 +++++++++++++++++-------------------- src/scanner.cc | 5 +- src/v8conversions.cc | 56 +++-------- src/v8conversions.h | 7 +- src/x64/full-codegen-x64.cc | 17 ++-- src/x64/lithium-codegen-x64.cc | 18 ++-- test/cctest/test-parsing.cc | 2 +- 34 files changed, 385 insertions(+), 448 deletions(-) diff --git a/src/accessors.cc b/src/accessors.cc index 8dbd9c9..8f77af0 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -80,10 +80,10 @@ MaybeObject* Accessors::ReadOnlySetAccessor(Isolate* isolate, static V8_INLINE bool CheckForName(Handle name, - String* property_name, + Handle property_name, int offset, int* object_offset) { - if (name->Equals(property_name)) { + if (String::Equals(name, property_name)) { *object_offset = offset; return true; } @@ -100,7 +100,7 @@ bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type, Isolate* isolate = name->GetIsolate(); if (type->Is(T::String())) { - return CheckForName(name, isolate->heap()->length_string(), + return CheckForName(name, isolate->factory()->length_string(), String::kLengthOffset, object_offset); } @@ -110,25 +110,25 @@ bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type, switch (map->instance_type()) { case JS_ARRAY_TYPE: return - CheckForName(name, isolate->heap()->length_string(), + CheckForName(name, isolate->factory()->length_string(), JSArray::kLengthOffset, object_offset); case JS_TYPED_ARRAY_TYPE: return - CheckForName(name, isolate->heap()->length_string(), + CheckForName(name, isolate->factory()->length_string(), JSTypedArray::kLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSTypedArray::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_offset_string(), + CheckForName(name, isolate->factory()->byte_offset_string(), JSTypedArray::kByteOffsetOffset, object_offset); case JS_ARRAY_BUFFER_TYPE: return - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSArrayBuffer::kByteLengthOffset, object_offset); case JS_DATA_VIEW_TYPE: return - CheckForName(name, isolate->heap()->byte_length_string(), + CheckForName(name, isolate->factory()->byte_length_string(), JSDataView::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->heap()->byte_offset_string(), + CheckForName(name, isolate->factory()->byte_offset_string(), JSDataView::kByteOffsetOffset, object_offset); default: return false; diff --git a/src/api.cc b/src/api.cc index 8d10163..90150b0 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3011,7 +3011,8 @@ bool Value::StrictEquals(Handle that) const { return other->IsNumber() && obj->Number() == other->Number(); } else if (obj->IsString()) { return other->IsString() && - i::String::cast(*obj)->Equals(i::String::cast(*other)); + i::String::Equals(i::Handle::cast(obj), + i::Handle::cast(other)); } else if (obj->IsUndefined() || obj->IsUndetectableObject()) { return other->IsUndefined() || other->IsUndetectableObject(); } else { diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index ba5053f..4d6ffb9 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -4525,13 +4525,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { __ JumpIfSmi(r0, if_true); __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); __ cmp(r0, ip); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { __ JumpIfSmi(r0, if_false); // Check for undetectable objects => false. __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE); @@ -4539,20 +4540,20 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); __ tst(r1, Operand(1 << Map::kIsUndetectable)); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { __ JumpIfSmi(r0, if_false); __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { __ CompareRoot(r0, Heap::kTrueValueRootIndex); __ b(eq, if_true); __ CompareRoot(r0, Heap::kFalseValueRootIndex); Split(eq, if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { __ CompareRoot(r0, Heap::kNullValueRootIndex); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); __ b(eq, if_true); __ JumpIfSmi(r0, if_false); @@ -4562,14 +4563,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ tst(r1, Operand(1 << Map::kIsUndetectable)); Split(ne, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(r0, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE); __ b(eq, if_true); __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE)); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(r0, if_false); if (!FLAG_harmony_typeof) { __ CompareRoot(r0, Heap::kNullValueRootIndex); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index b20c0e5..34d98b7 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5496,13 +5496,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, Handle type_name) { Condition final_branch_condition = kNoCondition; Register scratch = scratch0(); - if (type_name->Equals(heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(type_name, factory->number_string())) { __ JumpIfSmi(input, true_label); __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex); final_branch_condition = eq; - } else if (type_name->Equals(heap()->string_string())) { + } else if (String::Equals(type_name, factory->string_string())) { __ JumpIfSmi(input, false_label); __ CompareObjectType(input, scratch, no_reg, FIRST_NONSTRING_TYPE); __ b(ge, false_label); @@ -5510,22 +5511,23 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ tst(scratch, Operand(1 << Map::kIsUndetectable)); final_branch_condition = eq; - } else if (type_name->Equals(heap()->symbol_string())) { + } else if (String::Equals(type_name, factory->symbol_string())) { __ JumpIfSmi(input, false_label); __ CompareObjectType(input, scratch, no_reg, SYMBOL_TYPE); final_branch_condition = eq; - } else if (type_name->Equals(heap()->boolean_string())) { + } else if (String::Equals(type_name, factory->boolean_string())) { __ CompareRoot(input, Heap::kTrueValueRootIndex); __ b(eq, true_label); __ CompareRoot(input, Heap::kFalseValueRootIndex); final_branch_condition = eq; - } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { + } else if (FLAG_harmony_typeof && + String::Equals(type_name, factory->null_string())) { __ CompareRoot(input, Heap::kNullValueRootIndex); final_branch_condition = eq; - } else if (type_name->Equals(heap()->undefined_string())) { + } else if (String::Equals(type_name, factory->undefined_string())) { __ CompareRoot(input, Heap::kUndefinedValueRootIndex); __ b(eq, true_label); __ JumpIfSmi(input, false_label); @@ -5535,7 +5537,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ tst(scratch, Operand(1 << Map::kIsUndetectable)); final_branch_condition = ne; - } else if (type_name->Equals(heap()->function_string())) { + } else if (String::Equals(type_name, factory->function_string())) { STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); Register type_reg = scratch; __ JumpIfSmi(input, false_label); @@ -5544,7 +5546,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ cmp(type_reg, Operand(JS_FUNCTION_PROXY_TYPE)); final_branch_condition = eq; - } else if (type_name->Equals(heap()->object_string())) { + } else if (String::Equals(type_name, factory->object_string())) { Register map = scratch; __ JumpIfSmi(input, false_label); if (!FLAG_harmony_typeof) { diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 819868b..5679ccd 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -4238,13 +4238,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof number_string"); __ JumpIfSmi(x0, if_true); __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); __ CompareRoot(x0, Heap::kHeapNumberMapRootIndex); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof string_string"); __ JumpIfSmi(x0, if_false); // Check for undetectable objects => false. @@ -4252,22 +4253,22 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof symbol_string"); __ JumpIfSmi(x0, if_false); __ CompareObjectType(x0, x0, x1, SYMBOL_TYPE); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof boolean_string"); __ JumpIfRoot(x0, Heap::kTrueValueRootIndex, if_true); __ CompareRoot(x0, Heap::kFalseValueRootIndex); Split(eq, if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof null_string"); __ CompareRoot(x0, Heap::kNullValueRootIndex); Split(eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { ASM_LOCATION( "FullCodeGenerator::EmitLiteralCompareTypeof undefined_string"); __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, if_true); @@ -4277,7 +4278,7 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_false, if_true, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof function_string"); __ JumpIfSmi(x0, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); @@ -4285,7 +4286,7 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ CompareAndSplit(x11, JS_FUNCTION_PROXY_TYPE, eq, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof object_string"); __ JumpIfSmi(x0, if_false); if (!FLAG_harmony_typeof) { diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index d885edd..99f3b27 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -5715,7 +5715,8 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { Label* false_label = instr->FalseLabel(chunk_); Register value = ToRegister(instr->value()); - if (type_name->Equals(heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(type_name, factory->number_string())) { ASSERT(instr->temp1() != NULL); Register map = ToRegister(instr->temp1()); @@ -5724,7 +5725,7 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); EmitBranch(instr, eq); - } else if (type_name->Equals(heap()->string_string())) { + } else if (String::Equals(type_name, factory->string_string())) { ASSERT((instr->temp1() != NULL) && (instr->temp2() != NULL)); Register map = ToRegister(instr->temp1()); Register scratch = ToRegister(instr->temp2()); @@ -5735,7 +5736,7 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); EmitTestAndBranch(instr, eq, scratch, 1 << Map::kIsUndetectable); - } else if (type_name->Equals(heap()->symbol_string())) { + } else if (String::Equals(type_name, factory->symbol_string())) { ASSERT((instr->temp1() != NULL) && (instr->temp2() != NULL)); Register map = ToRegister(instr->temp1()); Register scratch = ToRegister(instr->temp2()); @@ -5744,16 +5745,17 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ CompareObjectType(value, map, scratch, SYMBOL_TYPE); EmitBranch(instr, eq); - } else if (type_name->Equals(heap()->boolean_string())) { + } else if (String::Equals(type_name, factory->boolean_string())) { __ JumpIfRoot(value, Heap::kTrueValueRootIndex, true_label); __ CompareRoot(value, Heap::kFalseValueRootIndex); EmitBranch(instr, eq); - } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { + } else if (FLAG_harmony_typeof && + String::Equals(type_name, factory->null_string())) { __ CompareRoot(value, Heap::kNullValueRootIndex); EmitBranch(instr, eq); - } else if (type_name->Equals(heap()->undefined_string())) { + } else if (String::Equals(type_name, factory->undefined_string())) { ASSERT(instr->temp1() != NULL); Register scratch = ToRegister(instr->temp1()); @@ -5764,7 +5766,7 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { __ Ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); EmitTestAndBranch(instr, ne, scratch, 1 << Map::kIsUndetectable); - } else if (type_name->Equals(heap()->function_string())) { + } else if (String::Equals(type_name, factory->function_string())) { STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); ASSERT(instr->temp1() != NULL); Register type = ToRegister(instr->temp1()); @@ -5774,7 +5776,7 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { // HeapObject's type has been loaded into type register by JumpIfObjectType. EmitCompareAndBranch(instr, eq, type, JS_FUNCTION_PROXY_TYPE); - } else if (type_name->Equals(heap()->object_string())) { + } else if (String::Equals(type_name, factory->object_string())) { ASSERT((instr->temp1() != NULL) && (instr->temp2() != NULL)); Register map = ToRegister(instr->temp1()); Register scratch = ToRegister(instr->temp2()); diff --git a/src/ast.cc b/src/ast.cc index b522c98..b9e0b38 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -78,7 +78,8 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const { // The global identifier "undefined" is immutable. Everything // else could be reassigned. return var != NULL && var->location() == Variable::UNALLOCATED && - var_proxy->name()->Equals(isolate->heap()->undefined_string()); + String::Equals(var_proxy->name(), + isolate->factory()->undefined_string()); } @@ -207,9 +208,10 @@ ObjectLiteralProperty::ObjectLiteralProperty( emit_store_ = true; key_ = key; value_ = value; - Object* k = *key->value(); + Handle k = key->value(); if (k->IsInternalizedString() && - zone->isolate()->heap()->proto_string()->Equals(String::cast(k))) { + String::Equals(Handle::cast(k), + zone->isolate()->factory()->proto_string())) { kind_ = PROTOTYPE; } else if (value_->AsMaterializedLiteral() != NULL) { kind_ = MATERIALIZED_LITERAL; diff --git a/src/ast.h b/src/ast.h index 486db60..ed3a8b6 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1394,7 +1394,7 @@ class Literal V8_FINAL : public Expression { static bool Match(void* literal1, void* literal2) { Handle s1 = static_cast(literal1)->ToString(); Handle s2 = static_cast(literal2)->ToString(); - return s1->Equals(*s2); + return String::Equals(s1, s2); } TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); } diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc index 64c1116..8f398e3 100644 --- a/src/compilation-cache.cc +++ b/src/compilation-cache.cc @@ -161,7 +161,8 @@ bool CompilationCacheScript::HasOrigin( // Were both scripts tagged by the embedder as being shared cross-origin? if (is_shared_cross_origin != script->is_shared_cross_origin()) return false; // Compare the two name strings for equality. - return String::cast(*name)->Equals(String::cast(script->name())); + return String::Equals(Handle::cast(name), + Handle(String::cast(script->name()))); } diff --git a/src/contexts.cc b/src/contexts.cc index 33d47e9..5ee0d4b 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -231,7 +231,7 @@ Handle Context::Lookup(Handle name, } else if (context->IsCatchContext()) { // Catch contexts have the variable name in the extension slot. - if (name->Equals(String::cast(context->extension()))) { + if (String::Equals(name, handle(String::cast(context->extension())))) { if (FLAG_trace_contexts) { PrintF("=> found in catch context\n"); } diff --git a/src/conversions.cc b/src/conversions.cc index 9c52d41..1d5ed35 100644 --- a/src/conversions.cc +++ b/src/conversions.cc @@ -56,7 +56,7 @@ double StringToDouble(UnicodeCache* unicode_cache, double StringToDouble(UnicodeCache* unicode_cache, - Vector str, + Vector str, int flags, double empty_string_val) { // We cast to const uint8_t* here to avoid instantiating the @@ -78,6 +78,23 @@ double StringToDouble(UnicodeCache* unicode_cache, } +// Converts a string into an integer. +double StringToInt(UnicodeCache* unicode_cache, + Vector vector, + int radix) { + return InternalStringToInt( + unicode_cache, vector.start(), vector.start() + vector.length(), radix); +} + + +double StringToInt(UnicodeCache* unicode_cache, + Vector vector, + int radix) { + return InternalStringToInt( + unicode_cache, vector.start(), vector.start() + vector.length(), radix); +} + + const char* DoubleToCString(double v, Vector buffer) { switch (fpclassify(v)) { case FP_NAN: return "NaN"; diff --git a/src/conversions.h b/src/conversions.h index f850f58..c8484e4 100644 --- a/src/conversions.h +++ b/src/conversions.h @@ -122,7 +122,7 @@ enum ConversionFlags { // Converts a string into a double value according to ECMA-262 9.3.1 double StringToDouble(UnicodeCache* unicode_cache, - Vector str, + Vector str, int flags, double empty_string_val = 0); double StringToDouble(UnicodeCache* unicode_cache, @@ -135,6 +135,16 @@ double StringToDouble(UnicodeCache* unicode_cache, int flags, double empty_string_val = 0); +// Converts a string into an integer. +double StringToInt(UnicodeCache* unicode_cache, + Vector vector, + int radix); + + +double StringToInt(UnicodeCache* unicode_cache, + Vector vector, + int radix); + const int kDoubleToCStringMinBufferSize = 100; // Converts a double to a string value according to ECMA-262 9.8.1. diff --git a/src/factory.cc b/src/factory.cc index 053f870..30e9c12 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -2009,10 +2009,9 @@ void Factory::ConfigureInstance(Handle desc, Handle Factory::GlobalConstantFor(Handle name) { - Heap* h = isolate()->heap(); - if (name->Equals(h->undefined_string())) return undefined_value(); - if (name->Equals(h->nan_string())) return nan_value(); - if (name->Equals(h->infinity_string())) return infinity_value(); + if (String::Equals(name, undefined_string())) return undefined_value(); + if (String::Equals(name, nan_string())) return nan_value(); + if (String::Equals(name, infinity_string())) return infinity_value(); return Handle::null(); } diff --git a/src/func-name-inferrer.cc b/src/func-name-inferrer.cc index e85e895..51ba4ad 100644 --- a/src/func-name-inferrer.cc +++ b/src/func-name-inferrer.cc @@ -55,14 +55,16 @@ void FuncNameInferrer::PushEnclosingName(Handle name) { void FuncNameInferrer::PushLiteralName(Handle name) { - if (IsOpen() && !isolate()->heap()->prototype_string()->Equals(*name)) { + if (IsOpen() && + !String::Equals(isolate()->factory()->prototype_string(), name)) { names_stack_.Add(Name(name, kLiteralName), zone()); } } void FuncNameInferrer::PushVariableName(Handle name) { - if (IsOpen() && !isolate()->heap()->dot_result_string()->Equals(*name)) { + if (IsOpen() && + !String::Equals(isolate()->factory()->dot_result_string(), name)) { names_stack_.Add(Name(name, kVariableName), zone()); } } diff --git a/src/heap-inl.h b/src/heap-inl.h index ea7dcda..f3ac56a 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -560,25 +560,6 @@ bool Heap::CollectGarbage(AllocationSpace space, } -MaybeObject* Heap::PrepareForCompare(String* str) { - // Always flatten small strings and force flattening of long strings - // after we have accumulated a certain amount we failed to flatten. - static const int kMaxAlwaysFlattenLength = 32; - static const int kFlattenLongThreshold = 16*KB; - - const int length = str->length(); - MaybeObject* obj = str->TryFlatten(); - if (length <= kMaxAlwaysFlattenLength || - unflattened_strings_length_ >= kFlattenLongThreshold) { - return obj; - } - if (obj->IsFailure()) { - unflattened_strings_length_ += length; - } - return str; -} - - int64_t Heap::AdjustAmountOfExternalAllocatedMemory( int64_t change_in_bytes) { ASSERT(HasBeenSetUp()); diff --git a/src/heap.h b/src/heap.h index 0f87fd1..7b3fed9 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1169,15 +1169,6 @@ class Heap { // NULL is returned if string is in new space or not flattened. Map* InternalizedStringMapForString(String* str); - // Tries to flatten a string before compare operation. - // - // Returns a failure in case it was decided that flattening was - // necessary and failed. Note, if flattening is not necessary the - // string might stay non-flat even when not a failure is returned. - // - // Please note this function does not perform a garbage collection. - MUST_USE_RESULT inline MaybeObject* PrepareForCompare(String* str); - // Converts the given boolean condition to JavaScript boolean value. inline Object* ToBoolean(bool condition); diff --git a/src/hydrogen.h b/src/hydrogen.h index 6d81307..ac6b99d 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2393,10 +2393,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { int offset; if (Accessors::IsJSObjectFieldAccessor(type_, name_, &offset)) { if (type_->Is(Type::String())) { - ASSERT(name_->Equals(isolate()->heap()->length_string())); + ASSERT(String::Equals(isolate()->factory()->length_string(), name_)); *access = HObjectAccess::ForStringLength(); } else if (type_->Is(Type::Array())) { - ASSERT(name_->Equals(isolate()->heap()->length_string())); + ASSERT(String::Equals(isolate()->factory()->length_string(), name_)); *access = HObjectAccess::ForArrayLength(map()->elements_kind()); } else { *access = HObjectAccess::ForMapAndOffset(map(), offset); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index b021e46..5622c30 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -4536,12 +4536,13 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { __ JumpIfSmi(eax, if_true); __ cmp(FieldOperand(eax, HeapObject::kMapOffset), isolate()->factory()->heap_number_map()); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); __ j(above_equal, if_false); @@ -4549,20 +4550,20 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ test_b(FieldOperand(edx, Map::kBitFieldOffset), 1 << Map::kIsUndetectable); Split(zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, SYMBOL_TYPE, edx); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { __ cmp(eax, isolate()->factory()->true_value()); __ j(equal, if_true); __ cmp(eax, isolate()->factory()->false_value()); Split(equal, if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { __ cmp(eax, isolate()->factory()->null_value()); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, if_true); __ JumpIfSmi(eax, if_false); @@ -4571,14 +4572,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); __ test(ecx, Immediate(1 << Map::kIsUndetectable)); Split(not_zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(eax, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); __ j(equal, if_true); __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(eax, if_false); if (!FLAG_harmony_typeof) { __ cmp(eax, isolate()->factory()->null_value()); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 66c4a5c..ebd430c 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -6094,13 +6094,13 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { Label::Distance false_distance = right_block == next_block ? Label::kNear : Label::kFar; Condition final_branch_condition = no_condition; - if (type_name->Equals(heap()->number_string())) { + if (String::Equals(type_name, factory()->number_string())) { __ JumpIfSmi(input, true_label, true_distance); __ cmp(FieldOperand(input, HeapObject::kMapOffset), factory()->heap_number_map()); final_branch_condition = equal; - } else if (type_name->Equals(heap()->string_string())) { + } else if (String::Equals(type_name, factory()->string_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); __ j(above_equal, false_label, false_distance); @@ -6108,22 +6108,23 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { 1 << Map::kIsUndetectable); final_branch_condition = zero; - } else if (type_name->Equals(heap()->symbol_string())) { + } else if (String::Equals(type_name, factory()->symbol_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, SYMBOL_TYPE, input); final_branch_condition = equal; - } else if (type_name->Equals(heap()->boolean_string())) { + } else if (String::Equals(type_name, factory()->boolean_string())) { __ cmp(input, factory()->true_value()); __ j(equal, true_label, true_distance); __ cmp(input, factory()->false_value()); final_branch_condition = equal; - } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { + } else if (FLAG_harmony_typeof && + String::Equals(type_name, factory()->null_string())) { __ cmp(input, factory()->null_value()); final_branch_condition = equal; - } else if (type_name->Equals(heap()->undefined_string())) { + } else if (String::Equals(type_name, factory()->undefined_string())) { __ cmp(input, factory()->undefined_value()); __ j(equal, true_label, true_distance); __ JumpIfSmi(input, false_label, false_distance); @@ -6133,7 +6134,7 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { 1 << Map::kIsUndetectable); final_branch_condition = not_zero; - } else if (type_name->Equals(heap()->function_string())) { + } else if (String::Equals(type_name, factory()->function_string())) { STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, JS_FUNCTION_TYPE, input); @@ -6141,7 +6142,7 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); final_branch_condition = equal; - } else if (type_name->Equals(heap()->object_string())) { + } else if (String::Equals(type_name, factory()->object_string())) { __ JumpIfSmi(input, false_label, false_distance); if (!FLAG_harmony_typeof) { __ cmp(input, factory()->null_value()); diff --git a/src/ic.cc b/src/ic.cc index 261d2e6..1e2f0b6 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -547,7 +547,7 @@ MaybeObject* LoadIC::Load(Handle object, if (FLAG_use_ic) { // Use specialized code for getting prototype of functions. if (object->IsJSFunction() && - name->Equals(isolate()->heap()->prototype_string()) && + String::Equals(isolate()->factory()->prototype_string(), name) && Handle::cast(object)->should_have_prototype()) { Handle stub; if (state() == UNINITIALIZED) { @@ -890,13 +890,14 @@ Handle LoadIC::CompileHandler(LookupResult* lookup, Handle name, Handle unused, InlineCacheHolderFlag cache_holder) { - if (object->IsString() && name->Equals(isolate()->heap()->length_string())) { + if (object->IsString() && + String::Equals(isolate()->factory()->length_string(), name)) { int length_index = String::kLengthOffset / kPointerSize; return SimpleFieldLoad(length_index); } if (object->IsStringWrapper() && - name->Equals(isolate()->heap()->length_string())) { + String::Equals(isolate()->factory()->length_string(), name)) { if (kind() == Code::LOAD_IC) { StringLengthStub string_length_stub; return string_length_stub.GetCode(isolate()); @@ -1216,7 +1217,7 @@ MaybeObject* StoreIC::Store(Handle object, // The length property of string values is read-only. Throw in strict mode. if (strict_mode() == STRICT && object->IsString() && - name->Equals(isolate()->heap()->length_string())) { + String::Equals(isolate()->factory()->length_string(), name)) { return TypeError("strict_read_only_property", object, name); } @@ -1403,7 +1404,7 @@ Handle StoreIC::CompileHandler(LookupResult* lookup, // properties. Slow properties might indicate redefinition of the length // property. if (receiver->IsJSArray() && - name->Equals(isolate()->heap()->length_string()) && + String::Equals(isolate()->factory()->length_string(), name) && Handle::cast(receiver)->AllowsSetElementsLength() && receiver->HasFastProperties()) { return compiler.CompileStoreArrayLength(receiver, lookup, name); diff --git a/src/json-parser.h b/src/json-parser.h index 5d8033a..a7dbd3a 100644 --- a/src/json-parser.h +++ b/src/json-parser.h @@ -539,17 +539,16 @@ Handle JsonParser::ParseJsonNumber() { if (seq_ascii) { Vector chars(seq_source_->GetChars() + beg_pos, length); number = StringToDouble(isolate()->unicode_cache(), - Vector::cast(chars), - NO_FLAGS, // Hex, octal or trailing junk. - OS::nan_value()); + chars, + NO_FLAGS, // Hex, octal or trailing junk. + OS::nan_value()); } else { Vector buffer = Vector::New(length); String::WriteToFlat(*source_, buffer.start(), beg_pos, position_); Vector result = Vector(buffer.start(), length); number = StringToDouble(isolate()->unicode_cache(), - // TODO(dcarney): Convert StringToDouble to uint_t. - Vector::cast(result), + result, NO_FLAGS, // Hex, octal or trailing junk. 0.0); buffer.Dispose(); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index dfbe37f..ef6bc84 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -4575,12 +4575,13 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { __ JumpIfSmi(v0, if_true); __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); Split(eq, v0, Operand(at), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { __ JumpIfSmi(v0, if_false); // Check for undetectable objects => false. __ GetObjectType(v0, v0, a1); @@ -4589,20 +4590,20 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { __ JumpIfSmi(v0, if_false); __ GetObjectType(v0, v0, a1); Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); __ LoadRoot(at, Heap::kFalseValueRootIndex); Split(eq, v0, Operand(at), if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { __ LoadRoot(at, Heap::kNullValueRootIndex); Split(eq, v0, Operand(at), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); __ JumpIfSmi(v0, if_false); @@ -4611,14 +4612,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(v0, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ GetObjectType(v0, v0, a1); __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE)); Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE), if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(v0, if_false); if (!FLAG_harmony_typeof) { __ LoadRoot(at, Heap::kNullValueRootIndex); diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 7c3f28f..14d4f14 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5524,7 +5524,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, // register. Condition final_branch_condition = kNoCondition; Register scratch = scratch0(); - if (type_name->Equals(heap()->number_string())) { + Factory* factory = isolate()->factory();facto + if (String::Equals(type_name, factory->number_string())) { __ JumpIfSmi(input, true_label); __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset)); __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); @@ -5532,7 +5533,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(at); final_branch_condition = eq; - } else if (type_name->Equals(heap()->string_string())) { + } else if (String::Equals(type_name, factory->string_string())) { __ JumpIfSmi(input, false_label); __ GetObjectType(input, input, scratch); __ Branch(USE_DELAY_SLOT, false_label, @@ -5545,14 +5546,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(zero_reg); final_branch_condition = eq; - } else if (type_name->Equals(heap()->symbol_string())) { + } else if (String::Equals(type_name, factory->symbol_string())) { __ JumpIfSmi(input, false_label); __ GetObjectType(input, input, scratch); cmp1 = scratch; cmp2 = Operand(SYMBOL_TYPE); final_branch_condition = eq; - } else if (type_name->Equals(heap()->boolean_string())) { + } else if (String::Equals(type_name, factory->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); __ LoadRoot(at, Heap::kFalseValueRootIndex); @@ -5560,13 +5561,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(input); final_branch_condition = eq; - } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { + } else if (FLAG_harmony_typeof && + String::Equals(type_name, factory->null_string())) { __ LoadRoot(at, Heap::kNullValueRootIndex); cmp1 = at; cmp2 = Operand(input); final_branch_condition = eq; - } else if (type_name->Equals(heap()->undefined_string())) { + } else if (String::Equals(type_name, factory->undefined_string())) { __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); // The first instruction of JumpIfSmi is an And - it is safe in the delay @@ -5580,7 +5582,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(zero_reg); final_branch_condition = ne; - } else if (type_name->Equals(heap()->function_string())) { + } else if (String::Equals(type_name, factory->function_string())) { STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label); __ GetObjectType(input, scratch, input); @@ -5589,7 +5591,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(JS_FUNCTION_PROXY_TYPE); final_branch_condition = eq; - } else if (type_name->Equals(heap()->object_string())) { + } else if (String::Equals(type_name, factory->object_string())) { __ JumpIfSmi(input, false_label); if (!FLAG_harmony_typeof) { __ LoadRoot(at, Heap::kNullValueRootIndex); diff --git a/src/objects-inl.h b/src/objects-inl.h index 461578b..cf7da15 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3043,6 +3043,17 @@ bool Name::Equals(Name* other) { } +bool Name::Equals(Handle one, Handle two) { + if (one.is_identical_to(two)) return true; + if ((one->IsInternalizedString() && two->IsInternalizedString()) || + one->IsSymbol() || two->IsSymbol()) { + return false; + } + return String::SlowEquals(Handle::cast(one), + Handle::cast(two)); +} + + ACCESSORS(Symbol, name, Object, kNameOffset) ACCESSORS(Symbol, flags, Smi, kFlagsOffset) BOOL_ACCESSORS(Symbol, flags, is_private, kPrivateBit) @@ -3057,6 +3068,15 @@ bool String::Equals(String* other) { } +bool String::Equals(Handle one, Handle two) { + if (one.is_identical_to(two)) return true; + if (one->IsInternalizedString() && two->IsInternalizedString()) { + return false; + } + return SlowEquals(one, two); +} + + Handle String::Flatten(Handle string, PretenureFlag pretenure) { if (!string->IsConsString()) return string; Handle cons = Handle::cast(string); @@ -3065,22 +3085,6 @@ Handle String::Flatten(Handle string, PretenureFlag pretenure) { } -MaybeObject* String::TryFlatten(PretenureFlag pretenure) { - if (!StringShape(this).IsCons()) return this; - ConsString* cons = ConsString::cast(this); - if (cons->IsFlat()) return cons->first(); - return SlowTryFlatten(pretenure); -} - - -String* String::TryFlattenGetString(PretenureFlag pretenure) { - MaybeObject* flat = TryFlatten(pretenure); - Object* successfully_flattened; - if (!flat->ToObject(&successfully_flattened)) return this; - return String::cast(successfully_flattened); -} - - uint16_t String::Get(int index) { ASSERT(index >= 0 && index < length()); switch (StringShape(this).full_representation_tag()) { diff --git a/src/objects.cc b/src/objects.cc index 789bfaf..402d8ae 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1214,73 +1214,11 @@ Handle String::SlowFlatten(Handle cons, } cons->set_first(*result); cons->set_second(isolate->heap()->empty_string()); + ASSERT(result->IsFlat()); return result; } -MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) { -#ifdef DEBUG - // Do not attempt to flatten in debug mode when allocation is not - // allowed. This is to avoid an assertion failure when allocating. - // Flattening strings is the only case where we always allow - // allocation because no GC is performed if the allocation fails. - if (!AllowHeapAllocation::IsAllowed()) return this; -#endif - - Heap* heap = GetHeap(); - switch (StringShape(this).representation_tag()) { - case kConsStringTag: { - ConsString* cs = ConsString::cast(this); - if (cs->second()->length() == 0) { - return cs->first(); - } - // There's little point in putting the flat string in new space if the - // cons string is in old space. It can never get GCed until there is - // an old space GC. - PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED; - int len = length(); - Object* object; - String* result; - if (IsOneByteRepresentation()) { - { MaybeObject* maybe_object = - heap->AllocateRawOneByteString(len, tenure); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - result = String::cast(object); - String* first = cs->first(); - int first_length = first->length(); - uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); - WriteToFlat(first, dest, 0, first_length); - String* second = cs->second(); - WriteToFlat(second, - dest + first_length, - 0, - len - first_length); - } else { - { MaybeObject* maybe_object = - heap->AllocateRawTwoByteString(len, tenure); - if (!maybe_object->ToObject(&object)) return maybe_object; - } - result = String::cast(object); - uc16* dest = SeqTwoByteString::cast(result)->GetChars(); - String* first = cs->first(); - int first_length = first->length(); - WriteToFlat(first, dest, 0, first_length); - String* second = cs->second(); - WriteToFlat(second, - dest + first_length, - 0, - len - first_length); - } - cs->set_first(result); - cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER); - return result; - } - default: - return this; - } -} - bool String::MakeExternal(v8::String::ExternalStringResource* resource) { // Externalizing twice leaks the external resource, so it's @@ -6070,18 +6008,6 @@ int Map::NextFreePropertyIndex() { } -AccessorDescriptor* Map::FindAccessor(Name* name) { - DescriptorArray* descs = instance_descriptors(); - int number_of_own_descriptors = NumberOfOwnDescriptors(); - for (int i = 0; i < number_of_own_descriptors; i++) { - if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { - return descs->GetCallbacks(i); - } - } - return NULL; -} - - void JSReceiver::LocalLookup( Name* name, LookupResult* result, bool search_hidden_prototypes) { ASSERT(name->IsName()); @@ -6577,8 +6503,8 @@ bool JSObject::DefineFastAccessor(Handle object, if (result.IsFound()) { Handle target(result.GetTransitionTarget()); int descriptor_number = target->LastAdded(); - ASSERT(target->instance_descriptors()->GetKey(descriptor_number) - ->Equals(*name)); + ASSERT(Name::Equals(name, + handle(target->instance_descriptors()->GetKey(descriptor_number)))); return TryAccessorTransition(object, target, descriptor_number, component, accessor, attributes); } @@ -8330,7 +8256,7 @@ String::FlatContent String::GetFlatContent() { } else { start = ExternalAsciiString::cast(string)->GetChars(); } - return FlatContent(Vector(start + offset, length)); + return FlatContent(start + offset, length); } else { ASSERT(shape.encoding_tag() == kTwoByteStringTag); const uc16* start; @@ -8339,7 +8265,7 @@ String::FlatContent String::GetFlatContent() { } else { start = ExternalTwoByteString::cast(string)->GetChars(); } - return FlatContent(Vector(start + offset, length)); + return FlatContent(start + offset, length); } } @@ -8979,6 +8905,7 @@ class StringComparator { bool String::SlowEquals(String* other) { + DisallowHeapAllocation no_gc; // Fast check: negative check with lengths. int len = length(); if (len != other->length()) return false; @@ -9008,14 +8935,10 @@ bool String::SlowEquals(String* other) { // before we try to flatten the strings. if (this->Get(0) != other->Get(0)) return false; - String* lhs = this->TryFlattenGetString(); - String* rhs = other->TryFlattenGetString(); - // TODO(dcarney): Compare all types of flat strings with a Visitor. - if (StringShape(lhs).IsSequentialAscii() && - StringShape(rhs).IsSequentialAscii()) { - const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars(); - const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars(); + if (IsSeqOneByteString() && other->IsSeqOneByteString()) { + const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); + const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); return CompareRawStringContents(str1, str2, len); } @@ -9023,7 +8946,57 @@ bool String::SlowEquals(String* other) { StringComparator comparator(isolate->objects_string_compare_iterator_a(), isolate->objects_string_compare_iterator_b()); - return comparator.Equals(static_cast(len), lhs, rhs); + return comparator.Equals(static_cast(len), this, other); +} + + +bool String::SlowEquals(Handle one, Handle two) { + // Fast check: negative check with lengths. + int one_length = one->length(); + if (one_length != two->length()) return false; + if (one_length == 0) return true; + + // Fast check: if hash code is computed for both strings + // a fast negative check can be performed. + if (one->HasHashCode() && two->HasHashCode()) { +#ifdef ENABLE_SLOW_ASSERTS + if (FLAG_enable_slow_asserts) { + if (one->Hash() != two->Hash()) { + bool found_difference = false; + for (int i = 0; i < one_length; i++) { + if (one->Get(i) != two->Get(i)) { + found_difference = true; + break; + } + } + ASSERT(found_difference); + } + } +#endif + if (one->Hash() != two->Hash()) return false; + } + + // We know the strings are both non-empty. Compare the first chars + // before we try to flatten the strings. + if (one->Get(0) != two->Get(0)) return false; + + one = String::Flatten(one); + two = String::Flatten(two); + + DisallowHeapAllocation no_gc; + String::FlatContent flat1 = one->GetFlatContent(); + String::FlatContent flat2 = two->GetFlatContent(); + + if (flat1.IsAscii() && flat2.IsAscii()) { + return CompareRawStringContents(flat1.ToOneByteVector().start(), + flat2.ToOneByteVector().start(), + one_length); + } else { + for (int i = 0; i < one_length; i++) { + if (flat1.Get(i) != flat2.Get(i)) return false; + } + return true; + } } diff --git a/src/objects.h b/src/objects.h index c8b2753..bb6b426 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6466,9 +6466,6 @@ class Map: public HeapObject { // Casting. static inline Map* cast(Object* obj); - // Locate an accessor in the instance descriptor. - AccessorDescriptor* FindAccessor(Name* name); - // Code cache operations. // Clears the code cache. @@ -8791,6 +8788,7 @@ class Name: public HeapObject { // Equality operations. inline bool Equals(Name* other); + inline static bool Equals(Handle one, Handle two); // Conversion. inline bool AsArrayIndex(uint32_t* index); @@ -8927,28 +8925,37 @@ class String: public Name { // true. Vector ToOneByteVector() { ASSERT_EQ(ASCII, state_); - return buffer_; + return Vector(onebyte_start, length_); } // Return the two-byte content of the string. Only use if IsTwoByte() // returns true. Vector ToUC16Vector() { ASSERT_EQ(TWO_BYTE, state_); - return Vector::cast(buffer_); + return Vector(twobyte_start, length_); + } + + uc16 Get(int i) { + ASSERT(i < length_); + ASSERT(state_ != NON_FLAT); + if (state_ == ASCII) return onebyte_start[i]; + return twobyte_start[i]; } private: enum State { NON_FLAT, ASCII, TWO_BYTE }; // Constructors only used by String::GetFlatContent(). - explicit FlatContent(Vector chars) - : buffer_(chars), - state_(ASCII) { } - explicit FlatContent(Vector chars) - : buffer_(Vector::cast(chars)), - state_(TWO_BYTE) { } - FlatContent() : buffer_(), state_(NON_FLAT) { } - - Vector buffer_; + explicit FlatContent(const uint8_t* start, int length) + : onebyte_start(start), length_(length), state_(ASCII) { } + explicit FlatContent(const uc16* start, int length) + : twobyte_start(start), length_(length), state_(TWO_BYTE) { } + FlatContent() : onebyte_start(NULL), length_(0), state_(NON_FLAT) { } + + union { + const uint8_t* onebyte_start; + const uc16* twobyte_start; + }; + int length_; State state_; friend class String; @@ -8986,7 +8993,7 @@ class String: public Name { // to this method are not efficient unless the string is flat. INLINE(uint16_t Get(int index)); - // Try to flatten the string. Checks first inline to see if it is + // Flattens the string. Checks first inline to see if it is // necessary. Does nothing if the string is not a cons string. // Flattening allocates a sequential string with the same data as // the given string and mutates the cons string to a degenerate @@ -8998,23 +9005,10 @@ class String: public Name { // // Degenerate cons strings are handled specially by the garbage // collector (see IsShortcutCandidate). - // - // Use FlattenString from Handles.cc to flatten even in case an - // allocation failure happens. - inline MaybeObject* TryFlatten(PretenureFlag pretenure = NOT_TENURED); - - // Convenience function. Has exactly the same behavior as - // TryFlatten(), except in the case of failure returns the original - // string. - inline String* TryFlattenGetString(PretenureFlag pretenure = NOT_TENURED); static inline Handle Flatten(Handle string, PretenureFlag pretenure = NOT_TENURED); - static Handle SlowFlatten(Handle cons, - PretenureFlag tenure); - - // Tries to return the content of a flat string as a structure holding either // a flat vector of char or of uc16. // If the string isn't flat, and therefore doesn't have flat content, the @@ -9032,6 +9026,7 @@ class String: public Name { // String equality operations. inline bool Equals(String* other); + inline static bool Equals(Handle one, Handle two); bool IsUtf8EqualTo(Vector str, bool allow_prefix_match = false); bool IsOneByteEqualTo(Vector str); bool IsTwoByteEqualTo(Vector str); @@ -9202,15 +9197,15 @@ class String: public Name { private: friend class Name; - // Try to flatten the top level ConsString that is hiding behind this - // string. This is a no-op unless the string is a ConsString. Flatten - // mutates the ConsString and might return a failure. - MUST_USE_RESULT MaybeObject* SlowTryFlatten(PretenureFlag pretenure); + static Handle SlowFlatten(Handle cons, + PretenureFlag tenure); // Slow case of String::Equals. This implementation works on any strings // but it is most efficient on strings that are almost flat. bool SlowEquals(String* other); + static bool SlowEquals(Handle one, Handle two); + // Slow case of AsArrayIndex. bool SlowAsArrayIndex(uint32_t* index); diff --git a/src/parser.cc b/src/parser.cc index a738634..a048e91 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1126,7 +1126,8 @@ void* Parser::ParseSourceElements(ZoneList* processor, // Check "use strict" directive (ES5 14.1). if (strict_mode() == SLOPPY && - directive->Equals(isolate()->heap()->use_strict_string()) && + String::Equals(isolate()->factory()->use_strict_string(), + directive) && token_loc.end_pos - token_loc.beg_pos == isolate()->heap()->use_strict_string()->length() + 2) { // TODO(mstarzinger): Global strict eval calls, need their own scope @@ -1195,8 +1196,8 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels, ExpressionStatement* estmt = stmt->AsExpressionStatement(); if (estmt != NULL && estmt->expression()->AsVariableProxy() != NULL && - estmt->expression()->AsVariableProxy()->name()->Equals( - isolate()->heap()->module_string()) && + String::Equals(isolate()->factory()->module_string(), + estmt->expression()->AsVariableProxy()->name()) && !scanner()->literal_contains_escapes()) { return ParseModuleDeclaration(NULL, ok); } @@ -2393,8 +2394,8 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, !scanner()->HasAnyLineTerminatorBeforeNext() && expr != NULL && expr->AsVariableProxy() != NULL && - expr->AsVariableProxy()->name()->Equals( - isolate()->heap()->native_string()) && + String::Equals(isolate()->factory()->native_string(), + expr->AsVariableProxy()->name()) && !scanner()->literal_contains_escapes()) { return ParseNativeDeclaration(ok); } @@ -2405,8 +2406,8 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, peek() != Token::IDENTIFIER || scanner()->HasAnyLineTerminatorBeforeNext() || expr->AsVariableProxy() == NULL || - !expr->AsVariableProxy()->name()->Equals( - isolate()->heap()->module_string()) || + !String::Equals(isolate()->factory()->module_string(), + expr->AsVariableProxy()->name()) || scanner()->literal_contains_escapes()) { ExpectSemicolon(CHECK_OK); } diff --git a/src/runtime.cc b/src/runtime.cc index f2e2650..00decf7 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4373,8 +4373,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); RUNTIME_ASSERT(start_index <= static_cast(sub->length())); - int position = - Runtime::StringMatch(isolate, sub, pat, start_index); + int position = Runtime::StringMatch(isolate, sub, pat, start_index); return Smi::FromInt(position); } @@ -4474,13 +4473,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { - SealHandleScope shs(isolate); + HandleScope handle_scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, str1, 0); - CONVERT_ARG_CHECKED(String, str2, 1); + CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); + CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); - if (str1 == str2) return Smi::FromInt(0); // Equal. + if (str1.is_identical_to(str2)) return Smi::FromInt(0); // Equal. int str1_length = str1->length(); int str2_length = str2->length(); @@ -4500,21 +4499,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { int d = str1->Get(0) - str2->Get(0); if (d != 0) return Smi::FromInt(d); - str1->TryFlatten(); - str2->TryFlatten(); + str1 = String::Flatten(str1); + str2 = String::Flatten(str2); - ConsStringIteratorOp* op1 = - isolate->runtime_state()->string_locale_compare_it1(); - ConsStringIteratorOp* op2 = - isolate->runtime_state()->string_locale_compare_it2(); - // TODO(dcarney) Can do array compares here more efficiently. - StringCharacterStream stream1(str1, op1); - StringCharacterStream stream2(str2, op2); + DisallowHeapAllocation no_gc; + String::FlatContent flat1 = str1->GetFlatContent(); + String::FlatContent flat2 = str2->GetFlatContent(); for (int i = 0; i < end; i++) { - uint16_t char1 = stream1.GetNext(); - uint16_t char2 = stream2.GetNext(); - if (char1 != char2) return Smi::FromInt(char1 - char2); + if (flat1.Get(i) != flat2.Get(i)) { + return Smi::FromInt(flat1.Get(i) - flat2.Get(i)); + } } return Smi::FromInt(str1_length - str2_length); @@ -6085,8 +6080,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { } // Handle special arguments properties. - if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n); - if (key->Equals(isolate->heap()->callee_string())) { + if (String::Equals(isolate->factory()->length_string(), key)) { + return Smi::FromInt(n); + } + if (String::Equals(isolate->factory()->callee_string(), key)) { JSFunction* function = frame->function(); if (function->shared()->strict_mode() == STRICT) { return isolate->Throw(*isolate->factory()->NewTypeError( @@ -6189,17 +6186,18 @@ static int ParseDecimalInteger(const uint8_t*s, int from, int to) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { - SealHandleScope shs(isolate); + HandleScope handle_scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(String, subject, 0); - subject->TryFlatten(); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); + subject = String::Flatten(subject); // Fast case: short integer or some sorts of junk values. - int len = subject->length(); if (subject->IsSeqOneByteString()) { + int len = subject->length(); if (len == 0) return Smi::FromInt(0); - uint8_t const* data = SeqOneByteString::cast(subject)->GetChars(); + DisallowHeapAllocation no_gc; + uint8_t const* data = Handle::cast(subject)->GetChars(); bool minus = (data[0] == '-'); int start_pos = (minus ? 1 : 0); @@ -6207,15 +6205,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { return isolate->heap()->nan_value(); } else if (data[start_pos] > '9') { // Fast check for a junk value. A valid string may start from a - // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or - // the 'I' character ('Infinity'). All of that have codes not greater than - // '9' except 'I' and  . + // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit + // or the 'I' character ('Infinity'). All of that have codes not greater + // than '9' except 'I' and  . if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { return isolate->heap()->nan_value(); } } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { - // The maximal/minimal smi has 10 digits. If the string has less digits we - // know it will fit into the smi-data type. + // The maximal/minimal smi has 10 digits. If the string has less digits + // we know it will fit into the smi-data type. int d = ParseDecimalInteger(data, start_pos, len); if (minus) { if (d == 0) return isolate->heap()->minus_zero_value(); @@ -6244,8 +6242,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 flags |= ALLOW_OCTAL | ALLOW_BINARY; } - return isolate->heap()->NumberFromDouble( - StringToDouble(isolate->unicode_cache(), subject, flags)); + + return *isolate->factory()->NewNumber(StringToDouble( + isolate->unicode_cache(), *subject, flags)); } @@ -6319,29 +6318,40 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { - SealHandleScope shs(isolate); - - CONVERT_ARG_CHECKED(String, s, 0); + HandleScope handle_scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); + RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); - s->TryFlatten(); + subject = String::Flatten(subject); + double value; - RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); - double value = StringToInt(isolate->unicode_cache(), s, radix); - return isolate->heap()->NumberFromDouble(value); + { DisallowHeapAllocation no_gc; + String::FlatContent flat = subject->GetFlatContent(); + + // ECMA-262 section 15.1.2.3, empty string is NaN + if (flat.IsAscii()) { + value = StringToInt( + isolate->unicode_cache(), flat.ToOneByteVector(), radix); + } else { + value = StringToInt( + isolate->unicode_cache(), flat.ToUC16Vector(), radix); + } + } + + return *isolate->factory()->NewNumber(value); } RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { - SealHandleScope shs(isolate); - CONVERT_ARG_CHECKED(String, str, 0); + HandleScope shs(isolate); + CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); - // ECMA-262 section 15.1.2.3, empty string is NaN - double value = StringToDouble(isolate->unicode_cache(), - str, ALLOW_TRAILING_JUNK, OS::nan_value()); + subject = String::Flatten(subject); + double value = StringToDouble( + isolate->unicode_cache(), *subject, ALLOW_TRAILING_JUNK, OS::nan_value()); - // Create a number object from the value. - return isolate->heap()->NumberFromDouble(value); + return *isolate->factory()->NewNumber(value); } @@ -7516,13 +7526,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { - SealHandleScope shs(isolate); + HandleScope handle_scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, x, 0); - CONVERT_ARG_CHECKED(String, y, 1); + CONVERT_ARG_HANDLE_CHECKED(String, x, 0); + CONVERT_ARG_HANDLE_CHECKED(String, y, 1); - bool not_equal = !x->Equals(y); + bool not_equal = !String::Equals(x, y); // This is slightly convoluted because the value that signifies // equality is 0 and inequality is 1 so we have to negate the result // from String::Equals. @@ -7623,27 +7633,33 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { } -static Object* StringCharacterStreamCompare(RuntimeState* state, - String* x, - String* y) { - StringCharacterStream stream_x(x, state->string_iterator_compare_x()); - StringCharacterStream stream_y(y, state->string_iterator_compare_y()); - while (stream_x.HasMore() && stream_y.HasMore()) { - int d = stream_x.GetNext() - stream_y.GetNext(); - if (d < 0) return Smi::FromInt(LESS); - else if (d > 0) return Smi::FromInt(GREATER); +RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StringCompare) { + HandleScope handle_scope(isolate); + ASSERT(args.length() == 2); + + CONVERT_ARG_HANDLE_CHECKED(String, x, 0); + CONVERT_ARG_HANDLE_CHECKED(String, y, 1); + + isolate->counters()->string_compare_runtime()->Increment(); + + // A few fast case tests before we flatten. + if (x.is_identical_to(y)) return Smi::FromInt(EQUAL); + if (y->length() == 0) { + if (x->length() == 0) return Smi::FromInt(EQUAL); + return Smi::FromInt(GREATER); + } else if (x->length() == 0) { + return Smi::FromInt(LESS); } - // x is (non-trivial) prefix of y: - if (stream_y.HasMore()) return Smi::FromInt(LESS); - // y is prefix of x: - return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL); -} + int d = x->Get(0) - y->Get(0); + if (d < 0) return Smi::FromInt(LESS); + else if (d > 0) return Smi::FromInt(GREATER); + // Slow case. + x = String::Flatten(x); + y = String::Flatten(y); -static Object* FlatStringCompare(String* x, String* y) { - ASSERT(x->IsFlat()); - ASSERT(y->IsFlat()); + DisallowHeapAllocation no_gc; Object* equal_prefix_result = Smi::FromInt(EQUAL); int prefix_length = x->length(); if (y->length() < prefix_length) { @@ -7653,7 +7669,6 @@ static Object* FlatStringCompare(String* x, String* y) { equal_prefix_result = Smi::FromInt(LESS); } int r; - DisallowHeapAllocation no_gc; String::FlatContent x_content = x->GetFlatContent(); String::FlatContent y_content = y->GetFlatContent(); if (x_content.IsAscii()) { @@ -7681,47 +7696,10 @@ static Object* FlatStringCompare(String* x, String* y) { } else { result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); } - ASSERT(result == - StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y)); return result; } -RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StringCompare) { - HandleScope shs(isolate); - ASSERT(args.length() == 2); - - CONVERT_ARG_CHECKED(String, x, 0); - CONVERT_ARG_CHECKED(String, y, 1); - - isolate->counters()->string_compare_runtime()->Increment(); - - // A few fast case tests before we flatten. - if (x == y) return Smi::FromInt(EQUAL); - if (y->length() == 0) { - if (x->length() == 0) return Smi::FromInt(EQUAL); - return Smi::FromInt(GREATER); - } else if (x->length() == 0) { - return Smi::FromInt(LESS); - } - - int d = x->Get(0) - y->Get(0); - if (d < 0) return Smi::FromInt(LESS); - else if (d > 0) return Smi::FromInt(GREATER); - - Object* obj; - { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - - return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) - : StringCharacterStreamCompare(isolate->runtime_state(), x, y); -} - - #define RUNTIME_UNARY_MATH(Name, name) \ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math##Name) { \ SealHandleScope shs(isolate); \ @@ -11596,7 +11574,7 @@ static bool SetContextLocalValue(Isolate* isolate, Handle new_value) { for (int i = 0; i < scope_info->ContextLocalCount(); i++) { Handle next_name(scope_info->ContextLocalName(i)); - if (variable_name->Equals(*next_name)) { + if (String::Equals(variable_name, next_name)) { VariableMode mode; InitializationFlag init_flag; int context_index = @@ -11628,7 +11606,8 @@ static bool SetLocalVariableValue(Isolate* isolate, // Parameters. for (int i = 0; i < scope_info->ParameterCount(); ++i) { - if (scope_info->ParameterName(i)->Equals(*variable_name)) { + HandleScope scope(isolate); + if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { frame->SetParameterValue(i, *new_value); // Argument might be shadowed in heap context, don't stop here. default_result = true; @@ -11637,7 +11616,8 @@ static bool SetLocalVariableValue(Isolate* isolate, // Stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { - if (scope_info->StackLocalName(i)->Equals(*variable_name)) { + HandleScope scope(isolate); + if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { frame->SetExpression(i, *new_value); return true; } @@ -11780,7 +11760,7 @@ static bool SetCatchVariableValue(Isolate* isolate, Handle new_value) { ASSERT(context->IsCatchContext()); Handle name(String::cast(context->extension())); - if (!name->Equals(*variable_name)) { + if (!String::Equals(name, variable_name)) { return false; } context->set(Context::THROWN_OBJECT_INDEX, *new_value); diff --git a/src/scanner.cc b/src/scanner.cc index 48bfd33..67211e0 100644 --- a/src/scanner.cc +++ b/src/scanner.cc @@ -1142,7 +1142,8 @@ Handle Scanner::AllocateInternalizedString(Isolate* isolate) { double Scanner::DoubleValue() { ASSERT(is_literal_one_byte()); return StringToDouble( - unicode_cache_, Vector::cast(literal_one_byte_string()), + unicode_cache_, + literal_one_byte_string(), ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY); } @@ -1201,7 +1202,7 @@ int DuplicateFinder::AddNumber(Vector key, int value) { int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY; double double_value = StringToDouble( - unicode_constants_, Vector::cast(key), flags, 0.0); + unicode_constants_, key, flags, 0.0); int length; const char* string; if (!std::isfinite(double_value)) { diff --git a/src/v8conversions.cc b/src/v8conversions.cc index 900b62d..b891a3e 100644 --- a/src/v8conversions.cc +++ b/src/v8conversions.cc @@ -30,6 +30,7 @@ #include "v8.h" +#include "assert-scope.h" #include "conversions-inl.h" #include "v8conversions.h" #include "dtoa.h" @@ -81,51 +82,18 @@ void StringCharacterStreamIterator::operator++() { double StringToDouble(UnicodeCache* unicode_cache, - String* str, int flags, double empty_string_val) { - StringShape shape(str); - // TODO(dcarney): Use a Visitor here. - if (shape.IsSequentialAscii()) { - const uint8_t* begin = SeqOneByteString::cast(str)->GetChars(); - const uint8_t* end = begin + str->length(); - return InternalStringToDouble(unicode_cache, begin, end, flags, - empty_string_val); - } else if (shape.IsSequentialTwoByte()) { - const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); - const uc16* end = begin + str->length(); - return InternalStringToDouble(unicode_cache, begin, end, flags, - empty_string_val); + String* string, + int flags, + double empty_string_val) { + DisallowHeapAllocation no_gc; + String::FlatContent flat = string->GetFlatContent(); + // ECMA-262 section 15.1.2.3, empty string is NaN + if (flat.IsAscii()) { + return StringToDouble( + unicode_cache, flat.ToOneByteVector(), flags, empty_string_val); } else { - ConsStringIteratorOp op; - StringCharacterStream stream(str, &op); - return InternalStringToDouble(unicode_cache, - StringCharacterStreamIterator(&stream), - StringCharacterStreamIterator::EndMarker(), - flags, - empty_string_val); - } -} - - -double StringToInt(UnicodeCache* unicode_cache, - String* str, - int radix) { - StringShape shape(str); - // TODO(dcarney): Use a Visitor here. - if (shape.IsSequentialAscii()) { - const uint8_t* begin = SeqOneByteString::cast(str)->GetChars(); - const uint8_t* end = begin + str->length(); - return InternalStringToInt(unicode_cache, begin, end, radix); - } else if (shape.IsSequentialTwoByte()) { - const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); - const uc16* end = begin + str->length(); - return InternalStringToInt(unicode_cache, begin, end, radix); - } else { - ConsStringIteratorOp op; - StringCharacterStream stream(str, &op); - return InternalStringToInt(unicode_cache, - StringCharacterStreamIterator(&stream), - StringCharacterStreamIterator::EndMarker(), - radix); + return StringToDouble( + unicode_cache, flat.ToUC16Vector(), flags, empty_string_val); } } diff --git a/src/v8conversions.h b/src/v8conversions.h index f2568c0..b38dde7 100644 --- a/src/v8conversions.h +++ b/src/v8conversions.h @@ -64,14 +64,11 @@ inline uint32_t NumberToUint32(Object* number) { } -// Converts a string into a double value according to ECMA-262 9.3.1 double StringToDouble(UnicodeCache* unicode_cache, - String* str, + String* string, int flags, - double empty_string_val = 0); + double empty_string_val = 0.0); -// Converts a string into an integer. -double StringToInt(UnicodeCache* unicode_cache, String* str, int radix); inline bool TryNumberToSize(Isolate* isolate, Object* number, size_t* result) { diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 8962267..1d5480f 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -4530,12 +4530,13 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, } PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - if (check->Equals(isolate()->heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(check, factory->number_string())) { __ JumpIfSmi(rax, if_true); __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->string_string())) { + } else if (String::Equals(check, factory->string_string())) { __ JumpIfSmi(rax, if_false); // Check for undetectable objects => false. __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); @@ -4543,20 +4544,20 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ testb(FieldOperand(rdx, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); Split(zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->symbol_string())) { + } else if (String::Equals(check, factory->symbol_string())) { __ JumpIfSmi(rax, if_false); __ CmpObjectType(rax, SYMBOL_TYPE, rdx); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->boolean_string())) { + } else if (String::Equals(check, factory->boolean_string())) { __ CompareRoot(rax, Heap::kTrueValueRootIndex); __ j(equal, if_true); __ CompareRoot(rax, Heap::kFalseValueRootIndex); Split(equal, if_true, if_false, fall_through); } else if (FLAG_harmony_typeof && - check->Equals(isolate()->heap()->null_string())) { + String::Equals(check, factory->null_string())) { __ CompareRoot(rax, Heap::kNullValueRootIndex); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->undefined_string())) { + } else if (String::Equals(check, factory->undefined_string())) { __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); __ j(equal, if_true); __ JumpIfSmi(rax, if_false); @@ -4565,14 +4566,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ testb(FieldOperand(rdx, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); Split(not_zero, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->function_string())) { + } else if (String::Equals(check, factory->function_string())) { __ JumpIfSmi(rax, if_false); STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); __ j(equal, if_true); __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE); Split(equal, if_true, if_false, fall_through); - } else if (check->Equals(isolate()->heap()->object_string())) { + } else if (String::Equals(check, factory->object_string())) { __ JumpIfSmi(rax, if_false); if (!FLAG_harmony_typeof) { __ CompareRoot(rax, Heap::kNullValueRootIndex); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index cdbeb1a..89f7cd0 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5371,14 +5371,15 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { Label::Distance false_distance = right_block == next_block ? Label::kNear : Label::kFar; Condition final_branch_condition = no_condition; - if (type_name->Equals(heap()->number_string())) { + Factory* factory = isolate()->factory(); + if (String::Equals(type_name, factory->number_string())) { __ JumpIfSmi(input, true_label, true_distance); __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); final_branch_condition = equal; - } else if (type_name->Equals(heap()->string_string())) { + } else if (String::Equals(type_name, factory->string_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); __ j(above_equal, false_label, false_distance); @@ -5386,22 +5387,23 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { Immediate(1 << Map::kIsUndetectable)); final_branch_condition = zero; - } else if (type_name->Equals(heap()->symbol_string())) { + } else if (String::Equals(type_name, factory->symbol_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, SYMBOL_TYPE, input); final_branch_condition = equal; - } else if (type_name->Equals(heap()->boolean_string())) { + } else if (String::Equals(type_name, factory->boolean_string())) { __ CompareRoot(input, Heap::kTrueValueRootIndex); __ j(equal, true_label, true_distance); __ CompareRoot(input, Heap::kFalseValueRootIndex); final_branch_condition = equal; - } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { + } else if (FLAG_harmony_typeof && + String::Equals(type_name, factory->null_string())) { __ CompareRoot(input, Heap::kNullValueRootIndex); final_branch_condition = equal; - } else if (type_name->Equals(heap()->undefined_string())) { + } else if (String::Equals(type_name, factory->undefined_string())) { __ CompareRoot(input, Heap::kUndefinedValueRootIndex); __ j(equal, true_label, true_distance); __ JumpIfSmi(input, false_label, false_distance); @@ -5411,7 +5413,7 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { Immediate(1 << Map::kIsUndetectable)); final_branch_condition = not_zero; - } else if (type_name->Equals(heap()->function_string())) { + } else if (String::Equals(type_name, factory->function_string())) { STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, JS_FUNCTION_TYPE, input); @@ -5419,7 +5421,7 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); final_branch_condition = equal; - } else if (type_name->Equals(heap()->object_string())) { + } else if (String::Equals(type_name, factory->object_string())) { __ JumpIfSmi(input, false_label, false_distance); if (!FLAG_harmony_typeof) { __ CompareRoot(input, Heap::kNullValueRootIndex); diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 286b859..80bd92f 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1368,7 +1368,7 @@ void TestParserSyncWithFlags(i::Handle source, } // Check that preparser and parser produce the same error. i::Handle preparser_message = FormatMessage(&data); - if (!message_string->Equals(*preparser_message)) { + if (!i::String::Equals(message_string, preparser_message)) { i::OS::Print( "Expected parser and preparser to produce the same error on:\n" "\t%s\n" -- 2.7.4