Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 5316) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -3423,8 +3423,10 @@ |
__ j(zero, &build_args); |
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); |
__ j(not_equal, &build_args); |
+ __ mov(ecx, FieldOperand(eax, JSFunction::kCodeEntryOffset)); |
+ __ sub(Operand(ecx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); |
- __ cmp(FieldOperand(eax, JSFunction::kCodeOffset), Immediate(apply_code)); |
+ __ cmp(Operand(ecx), Immediate(apply_code)); |
__ j(not_equal, &build_args); |
// Check that applicand is a function. |
@@ -5520,9 +5522,12 @@ |
class DeferredAllocateInNewSpace: public DeferredCode { |
public: |
- DeferredAllocateInNewSpace(int size, Register target) |
- : size_(size), target_(target) { |
+ DeferredAllocateInNewSpace(int size, |
+ Register target, |
+ int registers_to_save = 0) |
+ : size_(size), target_(target), registers_to_save_(registers_to_save) { |
ASSERT(size >= kPointerSize && size <= Heap::MaxObjectSizeInNewSpace()); |
+ ASSERT_EQ(0, registers_to_save & target.bit()); |
set_comment("[ DeferredAllocateInNewSpace"); |
} |
void Generate(); |
@@ -5530,15 +5535,28 @@ |
private: |
int size_; |
Register target_; |
+ int registers_to_save_; |
}; |
void DeferredAllocateInNewSpace::Generate() { |
+ for (int i = 0; i < kNumRegs; i++) { |
+ if (registers_to_save_ & (1 << i)) { |
+ Register save_register = { i }; |
+ __ push(save_register); |
+ } |
+ } |
__ push(Immediate(Smi::FromInt(size_))); |
__ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
if (!target_.is(eax)) { |
__ mov(target_, eax); |
} |
+ for (int i = kNumRegs - 1; i >= 0; i--) { |
+ if (registers_to_save_ & (1 << i)) { |
+ Register save_register = { i }; |
+ __ pop(save_register); |
+ } |
+ } |
} |
@@ -7362,6 +7380,89 @@ |
} |
+void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) { |
+ ASSERT_EQ(1, args->length()); |
+ |
+ Load(args->at(0)); |
+ Result object_result = frame_->Pop(); |
+ object_result.ToRegister(eax); |
+ object_result.Unuse(); |
+ { |
+ VirtualFrame::SpilledScope spilled_scope; |
+ |
+ Label done; |
+ |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &done); |
+ |
+ // Load JSRegExpResult map into edx. |
+ // Arguments to this function should be results of calling RegExp exec, |
+ // which is either an unmodified JSRegExpResult or null. Anything not having |
+ // the unmodified JSRegExpResult map is returned unmodified. |
+ // This also ensures that elements are fast. |
+ __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); |
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); |
+ __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); |
+ __ cmp(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
+ __ j(not_equal, &done); |
+ |
+ if (FLAG_debug_code) { |
+ // Check that object really has empty properties array, as the map |
+ // should guarantee. |
+ __ cmp(FieldOperand(eax, JSObject::kPropertiesOffset), |
+ Immediate(Factory::empty_fixed_array())); |
+ __ Check(equal, "JSRegExpResult: default map but non-empty properties."); |
+ } |
+ |
+ DeferredAllocateInNewSpace* allocate_fallback = |
+ new DeferredAllocateInNewSpace(JSRegExpResult::kSize, |
+ ebx, |
+ edx.bit() | eax.bit()); |
+ |
+ // All set, copy the contents to a new object. |
+ __ AllocateInNewSpace(JSRegExpResult::kSize, |
+ ebx, |
+ ecx, |
+ no_reg, |
+ allocate_fallback->entry_label(), |
+ TAG_OBJECT); |
+ __ bind(allocate_fallback->exit_label()); |
+ |
+ // Copy all fields from eax to ebx. |
+ STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0); |
+ // There is an even number of fields, so unroll the loop once |
+ // for efficiency. |
+ for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) { |
+ STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0); |
+ if (i != JSObject::kMapOffset) { |
+ // The map was already loaded into edx. |
+ __ mov(edx, FieldOperand(eax, i)); |
+ } |
+ __ mov(ecx, FieldOperand(eax, i + kPointerSize)); |
+ |
+ STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0); |
+ if (i == JSObject::kElementsOffset) { |
+ // If the elements array isn't empty, make it copy-on-write |
+ // before copying it. |
+ Label empty; |
+ __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array())); |
+ __ j(equal, &empty); |
+ ASSERT(!Heap::InNewSpace(Heap::fixed_cow_array_map())); |
+ __ mov(FieldOperand(edx, HeapObject::kMapOffset), |
+ Immediate(Factory::fixed_cow_array_map())); |
+ __ bind(&empty); |
+ } |
+ __ mov(FieldOperand(ebx, i), edx); |
+ __ mov(FieldOperand(ebx, i + kPointerSize), ecx); |
+ } |
+ __ mov(eax, ebx); |
+ |
+ __ bind(&done); |
+ } |
+ frame_->Push(eax); |
+} |
+ |
+ |
class DeferredSearchCache: public DeferredCode { |
public: |
DeferredSearchCache(Register dst, Register cache, Register key) |
@@ -9815,7 +9916,8 @@ |
// Initialize the code pointer in the function to be the one |
// found in the shared function info object. |
__ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
- __ mov(FieldOperand(eax, JSFunction::kCodeOffset), edx); |
+ __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
+ __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); |
// Return and remove the on-stack parameter. |
__ ret(1 * kPointerSize); |