| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 5232)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -6762,7 +6762,7 @@
|
| }
|
|
|
|
|
| - 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).
|
| @@ -6783,6 +6783,143 @@
|
| }
|
|
|
|
|
| +// 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')
|
|
|