}
+// Deferred code to check whether the String JavaScript object is safe for using
+// default value of. This code is called after the bit caching this information
+// in the map has been checked with the map for the object in the map_result_
+// register. On return the register map_result_ contains 1 for true and 0 for
+// false.
+class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
+ public:
+ DeferredIsStringWrapperSafeForDefaultValueOf(Register object,
+ Register map_result,
+ Register scratch1,
+ Register scratch2)
+ : object_(object),
+ map_result_(map_result),
+ scratch1_(scratch1),
+ scratch2_(scratch2) { }
+
+ virtual void Generate() {
+ Label false_result;
+
+ // Check that map is loaded as expected.
+ if (FLAG_debug_code) {
+ __ ldr(ip, FieldMemOperand(object_, HeapObject::kMapOffset));
+ __ cmp(map_result_, ip);
+ __ Assert(eq, "Map not in expected register");
+ }
+
+ // Check for fast case object. Generate false result for slow case object.
+ __ ldr(scratch1_, FieldMemOperand(object_, JSObject::kPropertiesOffset));
+ __ ldr(scratch1_, FieldMemOperand(scratch1_, HeapObject::kMapOffset));
+ __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+ __ cmp(scratch1_, ip);
+ __ b(eq, &false_result);
+
+ // Look for valueOf symbol in the descriptor array, and indicate false if
+ // found. The type is not checked, so if it is a transition it is a false
+ // negative.
+ __ ldr(map_result_,
+ FieldMemOperand(map_result_, Map::kInstanceDescriptorsOffset));
+ __ ldr(scratch2_, FieldMemOperand(map_result_, FixedArray::kLengthOffset));
+ // map_result_: descriptor array
+ // scratch2_: length of descriptor array
+ // Calculate the end of the descriptor array.
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagSize == 1);
+ STATIC_ASSERT(kPointerSize == 4);
+ __ add(scratch1_,
+ map_result_,
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ add(scratch1_,
+ scratch1_,
+ Operand(scratch2_, LSL, kPointerSizeLog2 - kSmiTagSize));
+
+ // Calculate location of the first key name.
+ __ add(map_result_,
+ map_result_,
+ Operand(FixedArray::kHeaderSize +
+ DescriptorArray::kFirstIndex * kPointerSize));
+ // Loop through all the keys in the descriptor array. If one of these is the
+ // symbol valueOf the result is false.
+ Label entry, loop;
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ ldr(scratch2_, FieldMemOperand(map_result_, 0));
+ __ cmp(scratch2_, Operand(Factory::value_of_symbol()));
+ __ b(eq, &false_result);
+ __ add(map_result_, map_result_, Operand(kPointerSize));
+ __ bind(&entry);
+ __ cmp(map_result_, Operand(scratch1_));
+ __ b(ne, &loop);
+
+ // Reload map as register map_result_ was used as temporary above.
+ __ ldr(map_result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+
+ // If a valueOf property is not found on the object check that it's
+ // prototype is the un-modified String prototype. If not result is false.
+ __ ldr(scratch1_, FieldMemOperand(map_result_, Map::kPrototypeOffset));
+ __ tst(scratch1_, Operand(kSmiTagMask));
+ __ b(eq, &false_result);
+ __ ldr(scratch1_, FieldMemOperand(scratch1_, HeapObject::kMapOffset));
+ __ ldr(scratch2_,
+ CodeGenerator::ContextOperand(cp, Context::GLOBAL_INDEX));
+ __ ldr(scratch2_,
+ FieldMemOperand(scratch2_, GlobalObject::kGlobalContextOffset));
+ __ ldr(scratch2_,
+ CodeGenerator::ContextOperand(
+ scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+ __ cmp(scratch1_, scratch2_);
+ __ b(ne, &false_result);
+
+ // Set the bit in the map to indicate that it has been checked safe for
+ // default valueOf and set true result.
+ __ ldr(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
+ __ orr(scratch1_,
+ scratch1_,
+ Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ str(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
+ __ mov(map_result_, Operand(1));
+ __ jmp(exit_label());
+ __ bind(&false_result);
+ // Set false result.
+ __ mov(map_result_, Operand(0));
+ }
+
+ private:
+ Register object_;
+ Register map_result_;
+ Register scratch1_;
+ Register scratch2_;
+};
+
+
+void CodeGenerator::GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Register obj = frame_->PopToRegister(); // Pop the string wrapper.
+ if (FLAG_debug_code) {
+ __ AbortIfSmi(obj);
+ }
+
+ // Check whether this map has already been checked to be safe for default
+ // valueOf.
+ Register map_result = VirtualFrame::scratch0();
+ __ ldr(map_result, FieldMemOperand(obj, HeapObject::kMapOffset));
+ __ ldrb(ip, FieldMemOperand(map_result, Map::kBitField2Offset));
+ __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ true_target()->Branch(ne);
+
+ // We need an additional two scratch registers for the deferred code.
+ Register scratch1 = VirtualFrame::scratch1();
+ // Use r6 without notifying the virtual frame.
+ Register scratch2 = r6;
+
+ DeferredIsStringWrapperSafeForDefaultValueOf* deferred =
+ new DeferredIsStringWrapperSafeForDefaultValueOf(
+ obj, map_result, scratch1, scratch2);
+ deferred->Branch(eq);
+ deferred->BindExit();
+ __ tst(map_result, Operand(map_result));
+ cc_reg_ = ne;
+}
+
+
void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (%_ClassOf(arg) === 'Function')
return inlined_write_barrier_size_ + 4;
}
+ static MemOperand ContextOperand(Register context, int index) {
+ return MemOperand(context, Context::SlotOffset(index));
+ }
+
private:
// Construction/Destruction
explicit CodeGenerator(MacroAssembler* masm);
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- static MemOperand ContextOperand(Register context, int index) {
- return MemOperand(context, Context::SlotOffset(index));
- }
-
MemOperand SlotOperand(Slot* slot, Register tmp);
MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
void GenerateIsSpecObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
+ void GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
}
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+
+ ASSERT(args->length() == 1);
+
+ VisitForValue(args->at(0), kAccumulator);
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
+ // used in a few functions in runtime.js which should not normally be hit by
+ // this compiler.
+ __ jmp(if_false);
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
}
+void MacroAssembler::AbortIfSmi(Register object) {
+ ASSERT_EQ(0, kSmiTag);
+ tst(object, Operand(kSmiTagMask));
+ Assert(ne, "Operand is a smi");
+}
+
+
void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
Register first,
Register second,
// Jump if either of the registers contain a smi.
void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
+ // Abort execution if argument is a smi. Used in debug code.
+ void AbortIfSmi(Register object);
+
// ---------------------------------------------------------------------------
// String utilities
InstallNativeFunctions();
+ // Store the map for the string prototype after the natives has been compiled
+ // and the String function has been setup.
+ Handle<JSFunction> string_function(global_context()->string_function());
+ ASSERT(JSObject::cast(
+ string_function->initial_map()->prototype())->HasFastProperties());
+ global_context()->set_string_function_prototype_map(
+ HeapObject::cast(string_function->initial_map()->prototype())->map());
+
InstallCustomCallGenerators();
// Install Function.prototype.call and apply.
F(IsObject, 1, 1) \
F(IsFunction, 1, 1) \
F(IsUndetectableObject, 1, 1) \
- F(IsSpecObject, 1, 1) \
+ F(IsSpecObject, 1, 1) \
+ F(IsStringWrapperSafeForDefaultValueOf, 1, 1) \
F(StringAdd, 2, 1) \
F(SubString, 3, 1) \
F(StringCompare, 2, 1) \
V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
+ V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
BOOLEAN_FUNCTION_INDEX,
NUMBER_FUNCTION_INDEX,
STRING_FUNCTION_INDEX,
+ STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
OBJECT_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
DATE_FUNCTION_INDEX,
EmitGetFromCache(expr->arguments());
} else if (strcmp("_IsRegExpEquivalent", *name->ToCString()) == 0) {
EmitIsRegExpEquivalent(expr->arguments());
+ } else if (strcmp("_IsStringWrapperSafeForDefaultValueOf",
+ *name->ToCString()) == 0) {
+ EmitIsStringWrapperSafeForDefaultValueOf(expr->arguments());
} else {
UNREACHABLE();
}
void EmitIsArray(ZoneList<Expression*>* arguments);
void EmitIsRegExp(ZoneList<Expression*>* arguments);
void EmitIsConstructCall(ZoneList<Expression*>* arguments);
+ void EmitIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* arguments);
void EmitObjectEquals(ZoneList<Expression*>* arguments);
void EmitArguments(ZoneList<Expression*>* arguments);
void EmitArgumentsLength(ZoneList<Expression*>* arguments);
}
- void CodeGenerator::GenerateIsSpecObject(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsSpecObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp' ||
// typeof(arg) == function).
}
+// Deferred code to check whether the String JavaScript object is safe for using
+// default value of. This code is called after the bit caching this information
+// in the map has been checked with the map for the object in the map_result_
+// register. On return the register map_result_ contains 1 for true and 0 for
+// false.
+class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
+ public:
+ DeferredIsStringWrapperSafeForDefaultValueOf(Register object,
+ Register map_result,
+ Register scratch1,
+ Register scratch2)
+ : object_(object),
+ map_result_(map_result),
+ scratch1_(scratch1),
+ scratch2_(scratch2) { }
+
+ virtual void Generate() {
+ Label false_result;
+
+ // Check that map is loaded as expected.
+ if (FLAG_debug_code) {
+ __ cmp(map_result_, FieldOperand(object_, HeapObject::kMapOffset));
+ __ Assert(equal, "Map not in expected register");
+ }
+
+ // Check for fast case object. Generate false result for slow case object.
+ __ mov(scratch1_, FieldOperand(object_, JSObject::kPropertiesOffset));
+ __ mov(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset));
+ __ cmp(scratch1_, Factory::hash_table_map());
+ __ j(equal, &false_result);
+
+ // Look for valueOf symbol in the descriptor array, and indicate false if
+ // found. The type is not checked, so if it is a transition it is a false
+ // negative.
+ __ mov(map_result_,
+ FieldOperand(map_result_, Map::kInstanceDescriptorsOffset));
+ __ mov(scratch1_, FieldOperand(map_result_, FixedArray::kLengthOffset));
+ // map_result_: descriptor array
+ // scratch1_: length of descriptor array
+ // Calculate the end of the descriptor array.
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagSize == 1);
+ STATIC_ASSERT(kPointerSize == 4);
+ __ lea(scratch1_,
+ Operand(map_result_, scratch1_, times_2, FixedArray::kHeaderSize));
+ // Calculate location of the first key name.
+ __ add(Operand(map_result_),
+ Immediate(FixedArray::kHeaderSize +
+ DescriptorArray::kFirstIndex * kPointerSize));
+ // Loop through all the keys in the descriptor array. If one of these is the
+ // symbol valueOf the result is false.
+ Label entry, loop;
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ mov(scratch2_, FieldOperand(map_result_, 0));
+ __ cmp(scratch2_, Factory::value_of_symbol());
+ __ j(equal, &false_result);
+ __ add(Operand(map_result_), Immediate(kPointerSize));
+ __ bind(&entry);
+ __ cmp(map_result_, Operand(scratch1_));
+ __ j(not_equal, &loop);
+
+ // Reload map as register map_result_ was used as temporary above.
+ __ mov(map_result_, FieldOperand(object_, HeapObject::kMapOffset));
+
+ // If a valueOf property is not found on the object check that it's
+ // prototype is the un-modified String prototype. If not result is false.
+ __ mov(scratch1_, FieldOperand(map_result_, Map::kPrototypeOffset));
+ __ test(scratch1_, Immediate(kSmiTagMask));
+ __ j(zero, &false_result);
+ __ mov(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset));
+ __ mov(scratch2_, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ mov(scratch2_,
+ FieldOperand(scratch2_, GlobalObject::kGlobalContextOffset));
+ __ cmp(scratch1_,
+ CodeGenerator::ContextOperand(
+ scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+ __ j(not_equal, &false_result);
+ // Set the bit in the map to indicate that it has been checked safe for
+ // default valueOf and set true result.
+ __ or_(FieldOperand(map_result_, Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ Set(map_result_, Immediate(1));
+ __ jmp(exit_label());
+ __ bind(&false_result);
+ // Set false result.
+ __ Set(map_result_, Immediate(0));
+ }
+
+ private:
+ Register object_;
+ Register map_result_;
+ Register scratch1_;
+ Register scratch2_;
+};
+
+
+void CodeGenerator::GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop(); // Pop the string wrapper.
+ obj.ToRegister();
+ ASSERT(obj.is_valid());
+ if (FLAG_debug_code) {
+ __ AbortIfSmi(obj.reg());
+ }
+
+ // Check whether this map has already been checked to be safe for default
+ // valueOf.
+ Result map_result = allocator()->Allocate();
+ ASSERT(map_result.is_valid());
+ __ mov(map_result.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+ __ test_b(FieldOperand(map_result.reg(), Map::kBitField2Offset),
+ 1 << Map::kStringWrapperSafeForDefaultValueOf);
+ destination()->true_target()->Branch(not_zero);
+
+ // We need an additional two scratch registers for the deferred code.
+ Result temp1 = allocator()->Allocate();
+ ASSERT(temp1.is_valid());
+ Result temp2 = allocator()->Allocate();
+ ASSERT(temp2.is_valid());
+
+ DeferredIsStringWrapperSafeForDefaultValueOf* deferred =
+ new DeferredIsStringWrapperSafeForDefaultValueOf(
+ obj.reg(), map_result.reg(), temp1.reg(), temp2.reg());
+ deferred->Branch(zero);
+ deferred->BindExit();
+ __ test(map_result.reg(), Operand(map_result.reg()));
+ obj.Unuse();
+ map_result.Unuse();
+ temp1.Unuse();
+ temp2.Unuse();
+ destination()->Split(not_equal);
+}
+
+
void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (%_ClassOf(arg) === 'Function')
return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
}
+ static Operand ContextOperand(Register context, int index) {
+ return Operand(context, Context::SlotOffset(index));
+ }
+
private:
// Construction/Destruction
explicit CodeGenerator(MacroAssembler* masm);
// The following are used by class Reference.
void LoadReference(Reference* ref);
- static Operand ContextOperand(Register context, int index) {
- return Operand(context, Context::SlotOffset(index));
- }
-
Operand SlotOperand(Slot* slot, Register tmp);
Operand ContextSlotOperandCheckExtensions(Slot* slot,
void GenerateIsSpecObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
+ void GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
}
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+
+ VisitForValue(args->at(0), kAccumulator);
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
+ // used in a few functions in runtime.js which should not normally be hit by
+ // this compiler.
+ __ jmp(if_false);
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
void MacroAssembler::AbortIfNotSmi(Register object) {
test(object, Immediate(kSmiTagMask));
- Assert(equal, "Operand not a smi");
+ Assert(equal, "Operand is not a smi");
}
void MacroAssembler::AbortIfSmi(Register object) {
test(object, Immediate(kSmiTagMask));
- Assert(not_equal, "Operand a smi");
+ Assert(not_equal, "Operand is a smi");
}
static const int kIsExtensible = 0;
static const int kFunctionWithPrototype = 1;
static const int kHasFastElements = 2;
+ static const int kStringWrapperSafeForDefaultValueOf = 3;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
// Left operand (this) is already a string.
function STRING_ADD_LEFT(y) {
if (!IS_STRING(y)) {
- if (IS_STRING_WRAPPER(y)) {
+ if (IS_STRING_WRAPPER(y) && %_IsStringWrapperSafeForDefaultValueOf(y)) {
y = %_ValueOf(y);
} else {
y = IS_NUMBER(y)
function STRING_ADD_RIGHT(y) {
var x = this;
if (!IS_STRING(x)) {
- if (IS_STRING_WRAPPER(x)) {
+ if (IS_STRING_WRAPPER(x) && %_IsStringWrapperSafeForDefaultValueOf(x)) {
x = %_ValueOf(x);
} else {
x = IS_NUMBER(x)
}
+// Deferred code to check whether the String JavaScript object is safe for using
+// default value of. This code is called after the bit caching this information
+// in the map has been checked with the map for the object in the map_result_
+// register. On return the register map_result_ contains 1 for true and 0 for
+// false.
+class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
+ public:
+ DeferredIsStringWrapperSafeForDefaultValueOf(Register object,
+ Register map_result,
+ Register scratch1,
+ Register scratch2)
+ : object_(object),
+ map_result_(map_result),
+ scratch1_(scratch1),
+ scratch2_(scratch2) { }
+
+ virtual void Generate() {
+ Label false_result;
+
+ // Check that map is loaded as expected.
+ if (FLAG_debug_code) {
+ __ cmpq(map_result_, FieldOperand(object_, HeapObject::kMapOffset));
+ __ Assert(equal, "Map not in expected register");
+ }
+
+ // Check for fast case object. Generate false result for slow case object.
+ __ movq(scratch1_, FieldOperand(object_, JSObject::kPropertiesOffset));
+ __ movq(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset));
+ __ CompareRoot(scratch1_, Heap::kHashTableMapRootIndex);
+ __ j(equal, &false_result);
+
+ // Look for valueOf symbol in the descriptor array, and indicate false if
+ // found. The type is not checked, so if it is a transition it is a false
+ // negative.
+ __ movq(map_result_,
+ FieldOperand(map_result_, Map::kInstanceDescriptorsOffset));
+ __ movq(scratch1_, FieldOperand(map_result_, FixedArray::kLengthOffset));
+ // map_result_: descriptor array
+ // scratch1_: length of descriptor array
+ // Calculate the end of the descriptor array.
+ SmiIndex index = masm_->SmiToIndex(scratch2_, scratch1_, kPointerSizeLog2);
+ __ lea(scratch1_,
+ Operand(
+ map_result_, index.reg, index.scale, FixedArray::kHeaderSize));
+ // Calculate location of the first key name.
+ __ addq(map_result_,
+ Immediate(FixedArray::kHeaderSize +
+ DescriptorArray::kFirstIndex * kPointerSize));
+ // Loop through all the keys in the descriptor array. If one of these is the
+ // symbol valueOf the result is false.
+ Label entry, loop;
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ movq(scratch2_, FieldOperand(map_result_, 0));
+ __ Cmp(scratch2_, Factory::value_of_symbol());
+ __ j(equal, &false_result);
+ __ addq(map_result_, Immediate(kPointerSize));
+ __ bind(&entry);
+ __ cmpq(map_result_, scratch1_);
+ __ j(not_equal, &loop);
+
+ // Reload map as register map_result_ was used as temporary above.
+ __ movq(map_result_, FieldOperand(object_, HeapObject::kMapOffset));
+
+ // If a valueOf property is not found on the object check that it's
+ // prototype is the un-modified String prototype. If not result is false.
+ __ movq(scratch1_, FieldOperand(map_result_, Map::kPrototypeOffset));
+ __ testq(scratch1_, Immediate(kSmiTagMask));
+ __ j(zero, &false_result);
+ __ movq(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset));
+ __ movq(scratch2_,
+ Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ movq(scratch2_,
+ FieldOperand(scratch2_, GlobalObject::kGlobalContextOffset));
+ __ cmpq(scratch1_,
+ CodeGenerator::ContextOperand(
+ scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+ __ j(not_equal, &false_result);
+ // Set the bit in the map to indicate that it has been checked safe for
+ // default valueOf and set true result.
+ __ or_(FieldOperand(map_result_, Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ Set(map_result_, 1);
+ __ jmp(exit_label());
+ __ bind(&false_result);
+ // Set false result.
+ __ Set(map_result_, 0);
+ }
+
+ private:
+ Register object_;
+ Register map_result_;
+ Register scratch1_;
+ Register scratch2_;
+};
+
+
+void CodeGenerator::GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+ Load(args->at(0));
+ Result obj = frame_->Pop(); // Pop the string wrapper.
+ obj.ToRegister();
+ ASSERT(obj.is_valid());
+ if (FLAG_debug_code) {
+ __ AbortIfSmi(obj.reg());
+ }
+
+ // Check whether this map has already been checked to be safe for default
+ // valueOf.
+ Result map_result = allocator()->Allocate();
+ ASSERT(map_result.is_valid());
+ __ movq(map_result.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
+ __ testb(FieldOperand(map_result.reg(), Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ destination()->true_target()->Branch(not_zero);
+
+ // We need an additional two scratch registers for the deferred code.
+ Result temp1 = allocator()->Allocate();
+ ASSERT(temp1.is_valid());
+ Result temp2 = allocator()->Allocate();
+ ASSERT(temp2.is_valid());
+
+ DeferredIsStringWrapperSafeForDefaultValueOf* deferred =
+ new DeferredIsStringWrapperSafeForDefaultValueOf(
+ obj.reg(), map_result.reg(), temp1.reg(), temp2.reg());
+ deferred->Branch(zero);
+ deferred->BindExit();
+ __ testq(map_result.reg(), map_result.reg());
+ obj.Unuse();
+ map_result.Unuse();
+ temp1.Unuse();
+ temp2.Unuse();
+ destination()->Split(not_equal);
+}
+
+
void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (%_ClassOf(arg) === 'Function')
// expected arguments. Otherwise return -1.
static int InlineRuntimeCallArgumentsCount(Handle<String> name);
+ static Operand ContextOperand(Register context, int index) {
+ return Operand(context, Context::SlotOffset(index));
+ }
+
private:
// Construction/Destruction
explicit CodeGenerator(MacroAssembler* masm);
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- static Operand ContextOperand(Register context, int index) {
- return Operand(context, Context::SlotOffset(index));
- }
-
Operand SlotOperand(Slot* slot, Register tmp);
Operand ContextSlotOperandCheckExtensions(Slot* slot,
void GenerateIsSpecObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
+ void GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
}
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+
+ VisitForValue(args->at(0), kAccumulator);
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
+ // used in a few functions in runtime.js which should not normally be hit by
+ // this compiler.
+ __ jmp(if_false);
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
}
+void MacroAssembler::AbortIfSmi(Register object) {
+ Label ok;
+ Condition is_smi = CheckSmi(object);
+ Assert(NegateCondition(is_smi), "Operand is a smi");
+}
+
+
void MacroAssembler::AbortIfNotSmi(Register object) {
Label ok;
Condition is_smi = CheckSmi(object);
- Assert(is_smi, "Operand not a smi");
+ Assert(is_smi, "Operand is not a smi");
}
// Abort execution if argument is not a number. Used in debug code.
void AbortIfNotNumber(Register object);
+ // Abort execution if argument is a smi. Used in debug code.
+ void AbortIfSmi(Register object);
+
// Abort execution if argument is not a smi. Used in debug code.
void AbortIfNotSmi(Register object);
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check that when valueOf for a String object is overwritten it is called and
+// the result used when that object is added with a string.
+
+// See: http://code.google.com/p/v8/issues/detail?id=760
+
+String.prototype.valueOf = function() { return 'y' };
+
+function test() {
+ var o = Object('x');
+ assertEquals('y', o + '');
+ assertEquals('y', '' + o);
+}
+
+for (var i = 0; i < 10; i++) {
+ var o = Object('x');
+ assertEquals('y', o + '');
+ assertEquals('y', '' + o);
+}
+
+for (var i = 0; i < 10; i++) {
+ test()
+}
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check that when valueOf for a String object is overwritten it is called and
+// the result used when that object is added with a string.
+
+// See: http://code.google.com/p/v8/issues/detail?id=760
+
+function test() {
+ var o = Object('x');
+ o.valueOf = function() { return 'y' };
+ assertEquals('y', o + '');
+ assertEquals('y', '' + o);
+}
+
+for (var i = 0; i < 10; i++) {
+ var o = Object('x');
+ o.valueOf = function() { return 'y' };
+ assertEquals('y', o + '');
+ assertEquals('y', '' + o);
+}
+
+for (var i = 0; i < 10; i++) {
+ test()
+}