[builtins] Remove STRING_ADD_LEFT and STRING_ADD_RIGHT builtins.
authorbmeurer <bmeurer@chromium.org>
Mon, 14 Sep 2015 08:40:44 +0000 (01:40 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 14 Sep 2015 08:41:35 +0000 (08:41 +0000)
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}

15 files changed:
src/contexts.h
src/full-codegen/arm/full-codegen-arm.cc
src/full-codegen/arm64/full-codegen-arm64.cc
src/full-codegen/full-codegen.h
src/full-codegen/ia32/full-codegen-ia32.cc
src/full-codegen/mips/full-codegen-mips.cc
src/full-codegen/mips64/full-codegen-mips64.cc
src/full-codegen/ppc/full-codegen-ppc.cc
src/full-codegen/x64/full-codegen-x64.cc
src/full-codegen/x87/full-codegen-x87.cc
src/hydrogen.cc
src/objects.h
src/runtime.js
src/runtime/runtime-strings.cc
src/runtime/runtime.h

index d562240..dd5e1ad 100644 (file)
@@ -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)                                     \
index f507cb1..22a2d33 100644 (file)
@@ -3325,95 +3325,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 9ad8e10..5363c02 100644 (file)
@@ -3031,108 +3031,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index da629d9..dc11d15 100644 (file)
@@ -510,7 +510,6 @@ class FullCodeGenerator: public AstVisitor {
   F(IsFunction)                           \
   F(IsSpecObject)                         \
   F(IsSimdValue)                          \
-  F(IsStringWrapperSafeForDefaultValueOf) \
   F(MathPow)                              \
   F(IsMinusZero)                          \
   F(HasCachedArrayIndex)                  \
index 3c18ac9..9729f59 100644 (file)
@@ -3214,97 +3214,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 2e3cb94..1bf21f0 100644 (file)
@@ -3318,94 +3318,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 6900a94..a273d57 100644 (file)
@@ -3320,95 +3320,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 10fdc24..81db6b3 100644 (file)
@@ -3316,97 +3316,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 3ba3464..3f0dec1 100644 (file)
@@ -3243,91 +3243,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index f801863..76682e3 100644 (file)
@@ -3204,97 +3204,6 @@ void FullCodeGenerator::EmitIsSimdValue(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* expr) {
-  ZoneList<Expression*>* 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<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 1);
index 79a9d5e..f417485 100644 (file)
@@ -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<HPushArguments>(left, right);
-        return AddUncasted<HInvokeFunction>(function, 2);
+        return AddUncasted<HCallRuntime>(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<HPushArguments>(left, right);
-        return AddUncasted<HInvokeFunction>(function, 2);
+        return AddUncasted<HCallRuntime>(Runtime::FunctionForId(Runtime::kAdd),
+                                         2);
       }
     }
 
index f547c83..9797f04 100644 (file)
@@ -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<bool, 2, 1> {};
   class ElementsKindBits: public BitField<ElementsKind, 3, 5> {};
 
index 11f0ab2..6df7faa 100644 (file)
@@ -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([
index 33625a1..0e6bf83 100644 (file)
@@ -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);
index 6800758..2b437da 100644 (file)
@@ -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)