From d90a404747bd065d2fe653704222b1e6638ef9e6 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Mon, 14 Sep 2015 01:40:44 -0700 Subject: [PATCH] [builtins] Remove STRING_ADD_LEFT and STRING_ADD_RIGHT builtins. These builtins present an optimization for the general addition case, where one side is already known to be a string. Unfortunately this optimization is wrong in the presence of @@toPrimitive (there are some ideas how to implement a similar optimization using the prototype backpointer mechanism that jkummerow@ introduced earlier). So this also removes the broken %_IsStringWrapperSafeForDefaultValueOf, which is the key part of the optimization mentioned above. R=mstarzinger@chromium.org BUG=v8:4307 LOG=n Review URL: https://codereview.chromium.org/1336273002 Cr-Commit-Position: refs/heads/master@{#30707} --- src/contexts.h | 24 +++--- src/full-codegen/arm/full-codegen-arm.cc | 89 --------------------- src/full-codegen/arm64/full-codegen-arm64.cc | 102 ------------------------- src/full-codegen/full-codegen.h | 1 - src/full-codegen/ia32/full-codegen-ia32.cc | 91 ---------------------- src/full-codegen/mips/full-codegen-mips.cc | 88 --------------------- src/full-codegen/mips64/full-codegen-mips64.cc | 89 --------------------- src/full-codegen/ppc/full-codegen-ppc.cc | 91 ---------------------- src/full-codegen/x64/full-codegen-x64.cc | 85 --------------------- src/full-codegen/x87/full-codegen-x87.cc | 91 ---------------------- src/hydrogen.cc | 14 ++-- src/objects.h | 2 +- src/runtime.js | 39 ---------- src/runtime/runtime-strings.cc | 6 -- src/runtime/runtime.h | 1 - 15 files changed, 20 insertions(+), 793 deletions(-) diff --git a/src/contexts.h b/src/contexts.h index d562240..dd5e1ad 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -90,19 +90,17 @@ enum BindingFlags { V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun) -#define NATIVE_CONTEXT_JS_BUILTINS(V) \ - V(APPLY_PREPARE_BUILTIN_INDEX, JSFunction, apply_prepare_builtin) \ - V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin) \ - V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin) \ - V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction, \ - concat_iterable_to_array_builtin) \ - V(EQUALS_BUILTIN_INDEX, JSFunction, equals_builtin) \ - V(REFLECT_APPLY_PREPARE_BUILTIN_INDEX, JSFunction, \ - reflect_apply_prepare_builtin) \ - V(REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX, JSFunction, \ - reflect_construct_prepare_builtin) \ - V(STRING_ADD_LEFT_BUILTIN_INDEX, JSFunction, string_add_left_builtin) \ - V(STRING_ADD_RIGHT_BUILTIN_INDEX, JSFunction, string_add_right_builtin) +#define NATIVE_CONTEXT_JS_BUILTINS(V) \ + V(APPLY_PREPARE_BUILTIN_INDEX, JSFunction, apply_prepare_builtin) \ + V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin) \ + V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin) \ + V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction, \ + concat_iterable_to_array_builtin) \ + V(EQUALS_BUILTIN_INDEX, JSFunction, equals_builtin) \ + V(REFLECT_APPLY_PREPARE_BUILTIN_INDEX, JSFunction, \ + reflect_apply_prepare_builtin) \ + V(REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX, JSFunction, \ + reflect_construct_prepare_builtin) #define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \ diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index f507cb1..22a2d33 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -3325,95 +3325,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(r0); - - __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset)); - __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ b(ne, &skip_lookup); - - // Check for fast case object. Generate false result for slow case object. - __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset)); - __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); - __ LoadRoot(ip, Heap::kHashTableMapRootIndex); - __ cmp(r2, ip); - __ b(eq, if_false); - - // Look for valueOf name in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(r3, r1); - __ cmp(r3, Operand::Zero()); - __ b(eq, &done); - - __ LoadInstanceDescriptors(r1, r4); - // r4: descriptor array. - // r3: valid entries in the descriptor array. - __ mov(ip, Operand(DescriptorArray::kDescriptorSize)); - __ mul(r3, r3, ip); - // Calculate location of the first key name. - __ add(r4, r4, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); - // Calculate the end of the descriptor array. - __ mov(r2, r4); - __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2)); - - // Loop through all the keys in the descriptor array. If one of these is the - // string "valueOf" the result is false. - // The use of ip to store the valueOf string assumes that it is not otherwise - // used in the loop below. - __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex); - __ jmp(&entry); - __ bind(&loop); - __ ldr(r3, MemOperand(r4, 0)); - __ cmp(r3, ip); - __ b(eq, if_false); - __ add(r4, r4, Operand(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ cmp(r4, Operand(r2)); - __ b(ne, &loop); - - __ bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); - __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset)); - __ JumpIfSmi(r2, if_false); - __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); - __ ldr(r3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); - __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset)); - __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - __ cmp(r2, r3); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 9ad8e10..5363c02 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -3031,108 +3031,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - Register object = x0; - __ AssertNotSmi(object); - - Register map = x10; - Register bitfield2 = x11; - __ Ldr(map, FieldMemOperand(object, HeapObject::kMapOffset)); - __ Ldrb(bitfield2, FieldMemOperand(map, Map::kBitField2Offset)); - __ Tbnz(bitfield2, Map::kStringWrapperSafeForDefaultValueOf, &skip_lookup); - - // Check for fast case object. Generate false result for slow case object. - Register props = x12; - Register props_map = x12; - Register hash_table_map = x13; - __ Ldr(props, FieldMemOperand(object, JSObject::kPropertiesOffset)); - __ Ldr(props_map, FieldMemOperand(props, HeapObject::kMapOffset)); - __ LoadRoot(hash_table_map, Heap::kHashTableMapRootIndex); - __ Cmp(props_map, hash_table_map); - __ B(eq, if_false); - - // Look for valueOf name in the descriptor array, and indicate false if found. - // Since we omit an enumeration index check, if it is added via a transition - // that shares its descriptor array, this is a false positive. - Label loop, done; - - // Skip loop if no descriptors are valid. - Register descriptors = x12; - Register descriptors_length = x13; - __ NumberOfOwnDescriptors(descriptors_length, map); - __ Cbz(descriptors_length, &done); - - __ LoadInstanceDescriptors(map, descriptors); - - // Calculate the end of the descriptor array. - Register descriptors_end = x14; - __ Mov(x15, DescriptorArray::kDescriptorSize); - __ Mul(descriptors_length, descriptors_length, x15); - // Calculate location of the first key name. - __ Add(descriptors, descriptors, - DescriptorArray::kFirstOffset - kHeapObjectTag); - // Calculate the end of the descriptor array. - __ Add(descriptors_end, descriptors, - Operand(descriptors_length, LSL, kPointerSizeLog2)); - - // Loop through all the keys in the descriptor array. If one of these is the - // string "valueOf" the result is false. - Register valueof_string = x1; - int descriptor_size = DescriptorArray::kDescriptorSize * kPointerSize; - __ LoadRoot(valueof_string, Heap::kvalueOf_stringRootIndex); - __ Bind(&loop); - __ Ldr(x15, MemOperand(descriptors, descriptor_size, PostIndex)); - __ Cmp(x15, valueof_string); - __ B(eq, if_false); - __ Cmp(descriptors, descriptors_end); - __ B(ne, &loop); - - __ Bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ Ldrb(x2, FieldMemOperand(map, Map::kBitField2Offset)); - __ Orr(x2, x2, 1 << Map::kStringWrapperSafeForDefaultValueOf); - __ Strb(x2, FieldMemOperand(map, Map::kBitField2Offset)); - - __ Bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its prototype - // is the unmodified String prototype. If not result is false. - Register prototype = x1; - Register global_idx = x2; - Register native_context = x2; - Register string_proto = x3; - Register proto_map = x4; - __ Ldr(prototype, FieldMemOperand(map, Map::kPrototypeOffset)); - __ JumpIfSmi(prototype, if_false); - __ Ldr(proto_map, FieldMemOperand(prototype, HeapObject::kMapOffset)); - __ Ldr(global_idx, GlobalObjectMemOperand()); - __ Ldr(native_context, - FieldMemOperand(global_idx, GlobalObject::kNativeContextOffset)); - __ Ldr(string_proto, - ContextMemOperand(native_context, - Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - __ Cmp(proto_map, string_proto); - - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h index da629d9..dc11d15 100644 --- a/src/full-codegen/full-codegen.h +++ b/src/full-codegen/full-codegen.h @@ -510,7 +510,6 @@ class FullCodeGenerator: public AstVisitor { F(IsFunction) \ F(IsSpecObject) \ F(IsSimdValue) \ - F(IsStringWrapperSafeForDefaultValueOf) \ F(MathPow) \ F(IsMinusZero) \ F(HasCachedArrayIndex) \ diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 3c18ac9..9729f59 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -3214,97 +3214,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(eax); - - // Check whether this map has already been checked to be safe for default - // valueOf. - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - __ test_b(FieldOperand(ebx, Map::kBitField2Offset), - 1 << Map::kStringWrapperSafeForDefaultValueOf); - __ j(not_zero, &skip_lookup); - - // Check for fast case object. Return false for slow case objects. - __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset)); - __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ cmp(ecx, isolate()->factory()->hash_table_map()); - __ j(equal, if_false); - - // Look for valueOf string in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(ecx, ebx); - __ cmp(ecx, 0); - __ j(equal, &done); - - __ LoadInstanceDescriptors(ebx, ebx); - // ebx: descriptor array. - // ecx: valid entries in the descriptor array. - // Calculate the end of the descriptor array. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize == 1); - STATIC_ASSERT(kPointerSize == 4); - __ imul(ecx, ecx, DescriptorArray::kDescriptorSize); - __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset)); - // Calculate location of the first key name. - __ add(ebx, Immediate(DescriptorArray::kFirstOffset)); - // Loop through all the keys in the descriptor array. If one of these is the - // internalized string "valueOf" the result is false. - __ jmp(&entry); - __ bind(&loop); - __ mov(edx, FieldOperand(ebx, 0)); - __ cmp(edx, isolate()->factory()->valueOf_string()); - __ j(equal, if_false); - __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ cmp(ebx, ecx); - __ j(not_equal, &loop); - - __ bind(&done); - - // Reload map as register ebx was used as temporary above. - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ or_(FieldOperand(ebx, Map::kBitField2Offset), - Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); - __ JumpIfSmi(ecx, if_false); - __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ mov(edx, - FieldOperand(edx, GlobalObject::kNativeContextOffset)); - __ cmp(ecx, - ContextOperand(edx, - Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index 2e3cb94..1bf21f0 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -3318,94 +3318,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(v0); - - __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); - __ lbu(t0, FieldMemOperand(a1, Map::kBitField2Offset)); - __ And(t0, t0, 1 << Map::kStringWrapperSafeForDefaultValueOf); - __ Branch(&skip_lookup, ne, t0, Operand(zero_reg)); - - // Check for fast case object. Generate false result for slow case object. - __ lw(a2, FieldMemOperand(v0, JSObject::kPropertiesOffset)); - __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset)); - __ LoadRoot(t0, Heap::kHashTableMapRootIndex); - __ Branch(if_false, eq, a2, Operand(t0)); - - // Look for valueOf name in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(a3, a1); - __ Branch(&done, eq, a3, Operand(zero_reg)); - - __ LoadInstanceDescriptors(a1, t0); - // t0: descriptor array. - // a3: valid entries in the descriptor array. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize == 1); - STATIC_ASSERT(kPointerSize == 4); - __ li(at, Operand(DescriptorArray::kDescriptorSize)); - __ Mul(a3, a3, at); - // Calculate location of the first key name. - __ Addu(t0, t0, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); - // Calculate the end of the descriptor array. - __ mov(a2, t0); - __ sll(t1, a3, kPointerSizeLog2); - __ Addu(a2, a2, t1); - - // Loop through all the keys in the descriptor array. If one of these is the - // string "valueOf" the result is false. - // The use of t2 to store the valueOf string assumes that it is not otherwise - // used in the loop below. - __ LoadRoot(t2, Heap::kvalueOf_stringRootIndex); - __ jmp(&entry); - __ bind(&loop); - __ lw(a3, MemOperand(t0, 0)); - __ Branch(if_false, eq, a3, Operand(t2)); - __ Addu(t0, t0, Operand(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ Branch(&loop, ne, t0, Operand(a2)); - - __ bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ lbu(a2, FieldMemOperand(a1, Map::kBitField2Offset)); - __ Or(a2, a2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset)); - __ JumpIfSmi(a2, if_false); - __ lw(a2, FieldMemOperand(a2, HeapObject::kMapOffset)); - __ lw(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); - __ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset)); - __ lw(a3, ContextOperand(a3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, a2, Operand(a3), if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index 6900a94..a273d57 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -3320,95 +3320,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(v0); - - __ ld(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); - __ lbu(a4, FieldMemOperand(a1, Map::kBitField2Offset)); - __ And(a4, a4, 1 << Map::kStringWrapperSafeForDefaultValueOf); - __ Branch(&skip_lookup, ne, a4, Operand(zero_reg)); - - // Check for fast case object. Generate false result for slow case object. - __ ld(a2, FieldMemOperand(v0, JSObject::kPropertiesOffset)); - __ ld(a2, FieldMemOperand(a2, HeapObject::kMapOffset)); - __ LoadRoot(a4, Heap::kHashTableMapRootIndex); - __ Branch(if_false, eq, a2, Operand(a4)); - - // Look for valueOf name in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(a3, a1); - __ Branch(&done, eq, a3, Operand(zero_reg)); - - __ LoadInstanceDescriptors(a1, a4); - // a4: descriptor array. - // a3: valid entries in the descriptor array. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize == 1); -// Does not need? -// STATIC_ASSERT(kPointerSize == 4); - __ li(at, Operand(DescriptorArray::kDescriptorSize)); - __ Dmul(a3, a3, at); - // Calculate location of the first key name. - __ Daddu(a4, a4, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); - // Calculate the end of the descriptor array. - __ mov(a2, a4); - __ dsll(a5, a3, kPointerSizeLog2); - __ Daddu(a2, a2, a5); - - // Loop through all the keys in the descriptor array. If one of these is the - // string "valueOf" the result is false. - // The use of a6 to store the valueOf string assumes that it is not otherwise - // used in the loop below. - __ LoadRoot(a6, Heap::kvalueOf_stringRootIndex); - __ jmp(&entry); - __ bind(&loop); - __ ld(a3, MemOperand(a4, 0)); - __ Branch(if_false, eq, a3, Operand(a6)); - __ Daddu(a4, a4, Operand(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ Branch(&loop, ne, a4, Operand(a2)); - - __ bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ lbu(a2, FieldMemOperand(a1, Map::kBitField2Offset)); - __ Or(a2, a2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ ld(a2, FieldMemOperand(a1, Map::kPrototypeOffset)); - __ JumpIfSmi(a2, if_false); - __ ld(a2, FieldMemOperand(a2, HeapObject::kMapOffset)); - __ ld(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); - __ ld(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset)); - __ ld(a3, ContextOperand(a3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, a2, Operand(a3), if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/ppc/full-codegen-ppc.cc b/src/full-codegen/ppc/full-codegen-ppc.cc index 10fdc24..81db6b3 100644 --- a/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/src/full-codegen/ppc/full-codegen-ppc.cc @@ -3316,97 +3316,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, &if_true, - &if_false, &fall_through); - - __ AssertNotSmi(r3); - - __ LoadP(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); - __ lbz(ip, FieldMemOperand(r4, Map::kBitField2Offset)); - __ andi(r0, ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ bne(&skip_lookup, cr0); - - // Check for fast case object. Generate false result for slow case object. - __ LoadP(r5, FieldMemOperand(r3, JSObject::kPropertiesOffset)); - __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset)); - __ LoadRoot(ip, Heap::kHashTableMapRootIndex); - __ cmp(r5, ip); - __ beq(if_false); - - // Look for valueOf name in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(r6, r4); - __ cmpi(r6, Operand::Zero()); - __ beq(&done); - - __ LoadInstanceDescriptors(r4, r7); - // r7: descriptor array. - // r6: valid entries in the descriptor array. - __ mov(ip, Operand(DescriptorArray::kDescriptorSize)); - __ Mul(r6, r6, ip); - // Calculate location of the first key name. - __ addi(r7, r7, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); - // Calculate the end of the descriptor array. - __ mr(r5, r7); - __ ShiftLeftImm(ip, r6, Operand(kPointerSizeLog2)); - __ add(r5, r5, ip); - - // Loop through all the keys in the descriptor array. If one of these is the - // string "valueOf" the result is false. - // The use of ip to store the valueOf string assumes that it is not otherwise - // used in the loop below. - __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex); - __ b(&entry); - __ bind(&loop); - __ LoadP(r6, MemOperand(r7, 0)); - __ cmp(r6, ip); - __ beq(if_false); - __ addi(r7, r7, Operand(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ cmp(r7, r5); - __ bne(&loop); - - __ bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ lbz(r5, FieldMemOperand(r4, Map::kBitField2Offset)); - __ ori(r5, r5, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ stb(r5, FieldMemOperand(r4, Map::kBitField2Offset)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset)); - __ JumpIfSmi(r5, if_false); - __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset)); - __ LoadP(r6, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); - __ LoadP(r6, FieldMemOperand(r6, GlobalObject::kNativeContextOffset)); - __ LoadP(r6, - ContextOperand(r6, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - __ cmp(r5, r6); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 3ba3464..3f0dec1 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -3243,91 +3243,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(rax); - - // Check whether this map has already been checked to be safe for default - // valueOf. - __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset)); - __ testb(FieldOperand(rbx, Map::kBitField2Offset), - Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ j(not_zero, &skip_lookup); - - // Check for fast case object. Generate false result for slow case object. - __ movp(rcx, FieldOperand(rax, JSObject::kPropertiesOffset)); - __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); - __ CompareRoot(rcx, Heap::kHashTableMapRootIndex); - __ j(equal, if_false); - - // Look for valueOf string in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(rcx, rbx); - __ cmpp(rcx, Immediate(0)); - __ j(equal, &done); - - __ LoadInstanceDescriptors(rbx, r8); - // rbx: descriptor array. - // rcx: valid entries in the descriptor array. - // Calculate the end of the descriptor array. - __ imulp(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize)); - __ leap(rcx, - Operand(r8, rcx, times_pointer_size, DescriptorArray::kFirstOffset)); - // Calculate location of the first key name. - __ addp(r8, Immediate(DescriptorArray::kFirstOffset)); - // Loop through all the keys in the descriptor array. If one of these is the - // internalized string "valueOf" the result is false. - __ jmp(&entry); - __ bind(&loop); - __ movp(rdx, FieldOperand(r8, 0)); - __ CompareRoot(rdx, Heap::kvalueOf_stringRootIndex); - __ j(equal, if_false); - __ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ cmpp(r8, rcx); - __ j(not_equal, &loop); - - __ bind(&done); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ orp(FieldOperand(rbx, Map::kBitField2Offset), - Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ movp(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); - __ testp(rcx, Immediate(kSmiTagMask)); - __ j(zero, if_false); - __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); - __ movp(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ movp(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset)); - __ cmpp(rcx, - ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index f801863..76682e3 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -3204,97 +3204,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) { } -void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( - CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false, skip_lookup; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ AssertNotSmi(eax); - - // Check whether this map has already been checked to be safe for default - // valueOf. - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - __ test_b(FieldOperand(ebx, Map::kBitField2Offset), - 1 << Map::kStringWrapperSafeForDefaultValueOf); - __ j(not_zero, &skip_lookup); - - // Check for fast case object. Return false for slow case objects. - __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset)); - __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ cmp(ecx, isolate()->factory()->hash_table_map()); - __ j(equal, if_false); - - // Look for valueOf string in the descriptor array, and indicate false if - // found. Since we omit an enumeration index check, if it is added via a - // transition that shares its descriptor array, this is a false positive. - Label entry, loop, done; - - // Skip loop if no descriptors are valid. - __ NumberOfOwnDescriptors(ecx, ebx); - __ cmp(ecx, 0); - __ j(equal, &done); - - __ LoadInstanceDescriptors(ebx, ebx); - // ebx: descriptor array. - // ecx: valid entries in the descriptor array. - // Calculate the end of the descriptor array. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize == 1); - STATIC_ASSERT(kPointerSize == 4); - __ imul(ecx, ecx, DescriptorArray::kDescriptorSize); - __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset)); - // Calculate location of the first key name. - __ add(ebx, Immediate(DescriptorArray::kFirstOffset)); - // Loop through all the keys in the descriptor array. If one of these is the - // internalized string "valueOf" the result is false. - __ jmp(&entry); - __ bind(&loop); - __ mov(edx, FieldOperand(ebx, 0)); - __ cmp(edx, isolate()->factory()->valueOf_string()); - __ j(equal, if_false); - __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize)); - __ bind(&entry); - __ cmp(ebx, ecx); - __ j(not_equal, &loop); - - __ bind(&done); - - // Reload map as register ebx was used as temporary above. - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - - // Set the bit in the map to indicate that there is no local valueOf field. - __ or_(FieldOperand(ebx, Map::kBitField2Offset), - Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); - - __ bind(&skip_lookup); - - // If a valueOf property is not found on the object check that its - // prototype is the un-modified String prototype. If not result is false. - __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); - __ JumpIfSmi(ecx, if_false); - __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ mov(edx, - FieldOperand(edx, GlobalObject::kNativeContextOffset)); - __ cmp(ecx, - ContextOperand(edx, - Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 79a9d5e..f417485 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -10995,10 +10995,11 @@ HValue* HGraphBuilder::BuildBinaryOperation( left = BuildNumberToString(left, left_type); } else if (!left_type->Is(Type::String())) { DCHECK(right_type->Is(Type::String())); - HValue* function = - AddLoadJSBuiltin(Context::STRING_ADD_RIGHT_BUILTIN_INDEX); + // TODO(bmeurer): We might want to optimize this, because we already + // know that the right hand side is a string. Add(left, right); - return AddUncasted(function, 2); + return AddUncasted(Runtime::FunctionForId(Runtime::kAdd), + 2); } // Convert right argument as necessary. @@ -11007,10 +11008,11 @@ HValue* HGraphBuilder::BuildBinaryOperation( right = BuildNumberToString(right, right_type); } else if (!right_type->Is(Type::String())) { DCHECK(left_type->Is(Type::String())); - HValue* function = - AddLoadJSBuiltin(Context::STRING_ADD_LEFT_BUILTIN_INDEX); + // TODO(bmeurer): We might want to optimize this, because we already + // know that the left hand side is a string. Add(left, right); - return AddUncasted(function, 2); + return AddUncasted(Runtime::FunctionForId(Runtime::kAdd), + 2); } } diff --git a/src/objects.h b/src/objects.h index f547c83..9797f04 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5790,7 +5790,7 @@ class Map: public HeapObject { // Bit positions for bit field 2 static const int kIsExtensible = 0; - static const int kStringWrapperSafeForDefaultValueOf = 1; + // Bit 1 is free. class IsPrototypeMapBits : public BitField {}; class ElementsKindBits: public BitField {}; diff --git a/src/runtime.js b/src/runtime.js index 11f0ab2..6df7faa 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -150,43 +150,6 @@ function COMPARE_STRONG(x, ncr) { } - -/* ----------------------------------- - - - - A r i t h m e t i c - - - - ----------------------------------- -*/ - -// Left operand (this) is already a string. -function STRING_ADD_LEFT(y) { - if (!IS_STRING(y)) { - if (IS_STRING_WRAPPER(y) && %_IsStringWrapperSafeForDefaultValueOf(y)) { - y = %_ValueOf(y); - } else { - y = IS_NUMBER(y) - ? %_NumberToString(y) - : %to_string_fun(%to_primitive(y, NO_HINT)); - } - } - return %_StringAdd(this, y); -} - - -// Right operand (y) is already a string. -function STRING_ADD_RIGHT(y) { - var x = this; - if (!IS_STRING(x)) { - if (IS_STRING_WRAPPER(x) && %_IsStringWrapperSafeForDefaultValueOf(x)) { - x = %_ValueOf(x); - } else { - x = IS_NUMBER(x) - ? %_NumberToString(x) - : %to_string_fun(%to_primitive(x, NO_HINT)); - } - } - return %_StringAdd(x, y); -} - - /* ----------------------------- - - - H e l p e r s - - - ----------------------------- @@ -538,8 +501,6 @@ $toString = ToString; "equals_builtin", EQUALS, "reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE, "reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE, - "string_add_left_builtin", STRING_ADD_LEFT, - "string_add_right_builtin", STRING_ADD_RIGHT, ]); %InstallToContext([ diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc index 33625a1..0e6bf83 100644 --- a/src/runtime/runtime-strings.cc +++ b/src/runtime/runtime-strings.cc @@ -1322,12 +1322,6 @@ RUNTIME_FUNCTION(Runtime_StringCharCodeAt) { } -RUNTIME_FUNCTION(Runtime_IsStringWrapperSafeForDefaultValueOf) { - UNIMPLEMENTED(); - return NULL; -} - - RUNTIME_FUNCTION(Runtime_StringGetLength) { HandleScope scope(isolate); DCHECK(args.length() == 1); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 6800758..2b437da 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -921,7 +921,6 @@ namespace internal { F(TwoByteSeqStringGetChar, 2, 1) \ F(TwoByteSeqStringSetChar, 3, 1) \ F(StringCharCodeAt, 2, 1) \ - F(IsStringWrapperSafeForDefaultValueOf, 1, 1) \ F(StringGetLength, 1, 1) -- 2.7.4