Push version 2.1.1 to trunk.
[ES5] Implemented Object.defineProperty.
Improved profiler support.
Added SetPrototype method in the public V8 API.
Added GetScriptOrigin and GetScriptLineNumber methods to Function objects in the API.
Performance improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@3905 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index b39404e..b249d69 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -37,7 +37,6 @@
MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size),
- unresolved_(0),
generating_stub_(false),
allow_stub_calls_(true),
code_object_(Heap::undefined_value()) {
@@ -196,7 +195,7 @@
void MacroAssembler::LoadRoot(Register destination,
Heap::RootListIndex index,
Condition cond) {
- ldr(destination, MemOperand(r10, index << kPointerSizeLog2), cond);
+ ldr(destination, MemOperand(roots, index << kPointerSizeLog2), cond);
}
@@ -331,14 +330,10 @@
// Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
- mov(fp, Operand(sp)); // setup new frame pointer
+ mov(fp, Operand(sp)); // Setup new frame pointer.
- if (mode == ExitFrame::MODE_DEBUG) {
- mov(ip, Operand(Smi::FromInt(0)));
- } else {
- mov(ip, Operand(CodeObject()));
- }
- push(ip);
+ mov(ip, Operand(CodeObject()));
+ push(ip); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
@@ -550,6 +545,21 @@
}
+void MacroAssembler::InvokeFunction(JSFunction* function,
+ const ParameterCount& actual,
+ InvokeFlag flag) {
+ ASSERT(function->is_compiled());
+
+ // Get the function and setup the context.
+ mov(r1, Operand(Handle<JSFunction>(function)));
+ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+
+ // Invoke the cached code.
+ Handle<Code> code(function->code());
+ ParameterCount expected(function->shared()->formal_parameter_count());
+ InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
+}
+
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
@@ -608,6 +618,15 @@
}
}
}
+
+
+void MacroAssembler::DebugBreak() {
+ ASSERT(allow_stub_calls());
+ mov(r0, Operand(0));
+ mov(r1, Operand(ExternalReference(Runtime::kDebugBreak)));
+ CEntryStub ces(1);
+ Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+}
#endif
@@ -940,6 +959,113 @@
}
+void MacroAssembler::AllocateTwoByteString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required) {
+ // Calculate the number of bytes needed for the characters in the string while
+ // observing object alignment.
+ ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+ mov(scratch1, Operand(length, LSL, 1)); // Length in bytes, not chars.
+ add(scratch1, scratch1,
+ Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
+ // AllocateInNewSpace expects the size in words, so we can round down
+ // to kObjectAlignment and divide by kPointerSize in the same shift.
+ ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
+ mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
+
+ // Allocate two-byte string in new space.
+ AllocateInNewSpace(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map, length and hash field.
+ LoadRoot(scratch1, Heap::kStringMapRootIndex);
+ str(length, FieldMemOperand(result, String::kLengthOffset));
+ str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ mov(scratch2, Operand(String::kEmptyHashField));
+ str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
+}
+
+
+void MacroAssembler::AllocateAsciiString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required) {
+ // Calculate the number of bytes needed for the characters in the string while
+ // observing object alignment.
+ ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
+ ASSERT(kCharSize == 1);
+ add(scratch1, length,
+ Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize));
+ // AllocateInNewSpace expects the size in words, so we can round down
+ // to kObjectAlignment and divide by kPointerSize in the same shift.
+ ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
+ mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
+
+ // Allocate ASCII string in new space.
+ AllocateInNewSpace(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map, length and hash field.
+ LoadRoot(scratch1, Heap::kAsciiStringMapRootIndex);
+ mov(scratch1, Operand(Factory::ascii_string_map()));
+ str(length, FieldMemOperand(result, String::kLengthOffset));
+ str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ mov(scratch2, Operand(String::kEmptyHashField));
+ str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
+}
+
+
+void MacroAssembler::AllocateTwoByteConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(ConsString::kSize / kPointerSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+ LoadRoot(scratch1, Heap::kConsStringMapRootIndex);
+ mov(scratch2, Operand(String::kEmptyHashField));
+ str(length, FieldMemOperand(result, String::kLengthOffset));
+ str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
+}
+
+
+void MacroAssembler::AllocateAsciiConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(ConsString::kSize / kPointerSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+ LoadRoot(scratch1, Heap::kConsAsciiStringMapRootIndex);
+ mov(scratch2, Operand(String::kEmptyHashField));
+ str(length, FieldMemOperand(result, String::kLengthOffset));
+ str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ str(scratch2, FieldMemOperand(result, String::kHashFieldOffset));
+}
+
+
void MacroAssembler::CompareObjectType(Register function,
Register map,
Register type_reg,
@@ -957,6 +1083,21 @@
}
+void MacroAssembler::CheckMap(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Label* fail,
+ bool is_heap_object) {
+ if (!is_heap_object) {
+ BranchOnSmi(obj, fail);
+ }
+ ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+ mov(ip, Operand(map));
+ cmp(scratch, ip);
+ b(ne, fail);
+}
+
+
void MacroAssembler::TryGetFunctionPrototype(Register function,
Register result,
Register scratch,
@@ -1010,10 +1151,17 @@
}
+void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
+ ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs
+ Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
+}
+
+
void MacroAssembler::StubReturn(int argc) {
ASSERT(argc >= 1 && generating_stub());
- if (argc > 1)
+ if (argc > 1) {
add(sp, sp, Operand((argc - 1) * kPointerSize));
+ }
Ret();
}
@@ -1037,6 +1185,18 @@
}
+void MacroAssembler::GetLeastBitsFromSmi(Register dst,
+ Register src,
+ int num_least_bits) {
+ if (CpuFeatures::IsSupported(ARMv7)) {
+ ubfx(dst, src, Operand(kSmiTagSize), Operand(num_least_bits - 1));
+ } else {
+ mov(dst, Operand(src, ASR, kSmiTagSize));
+ and_(dst, dst, Operand((1 << num_least_bits) - 1));
+ }
+}
+
+
void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// All parameters are on the stack. r0 has the return value after call.
@@ -1064,6 +1224,16 @@
}
+void MacroAssembler::CallExternalReference(const ExternalReference& ext,
+ int num_arguments) {
+ mov(r0, Operand(num_arguments));
+ mov(r1, Operand(ext));
+
+ CEntryStub stub(1);
+ CallStub(&stub);
+}
+
+
void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
int num_arguments,
int result_size) {
@@ -1087,58 +1257,28 @@
}
-Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
- bool* resolved) {
- // Contract with compiled functions is that the function is passed in r1.
- int builtins_offset =
- JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
- ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
- ldr(r1, FieldMemOperand(r1, builtins_offset));
-
- return Builtins::GetCode(id, resolved);
-}
-
-
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags) {
- bool resolved;
- Handle<Code> code = ResolveBuiltin(id, &resolved);
-
+ GetBuiltinEntry(r2, id);
if (flags == CALL_JS) {
- Call(code, RelocInfo::CODE_TARGET);
+ Call(r2);
} else {
ASSERT(flags == JUMP_JS);
- Jump(code, RelocInfo::CODE_TARGET);
- }
-
- if (!resolved) {
- const char* name = Builtins::GetName(id);
- int argc = Builtins::GetArgumentsCount(id);
- uint32_t flags =
- Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsUseCodeObject::encode(false);
- Unresolved entry = { pc_offset() - kInstrSize, flags, name };
- unresolved_.Add(entry);
+ Jump(r2);
}
}
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- bool resolved;
- Handle<Code> code = ResolveBuiltin(id, &resolved);
-
- mov(target, Operand(code));
- if (!resolved) {
- const char* name = Builtins::GetName(id);
- int argc = Builtins::GetArgumentsCount(id);
- uint32_t flags =
- Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsUseCodeObject::encode(true);
- Unresolved entry = { pc_offset() - kInstrSize, flags, name };
- unresolved_.Add(entry);
- }
-
+ // Load the JavaScript builtin function from the builtins object.
+ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
+ int builtins_offset =
+ JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
+ ldr(r1, FieldMemOperand(r1, builtins_offset));
+ // Load the code entry point from the function into the target register.
+ ldr(target, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ ldr(target, FieldMemOperand(target, SharedFunctionInfo::kCodeOffset));
add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
}
@@ -1238,6 +1378,26 @@
}
+void MacroAssembler::JumpIfNotBothSmi(Register reg1,
+ Register reg2,
+ Label* on_not_both_smi) {
+ ASSERT_EQ(0, kSmiTag);
+ tst(reg1, Operand(kSmiTagMask));
+ tst(reg2, Operand(kSmiTagMask), eq);
+ b(ne, on_not_both_smi);
+}
+
+
+void MacroAssembler::JumpIfEitherSmi(Register reg1,
+ Register reg2,
+ Label* on_either_smi) {
+ ASSERT_EQ(0, kSmiTag);
+ tst(reg1, Operand(kSmiTagMask));
+ tst(reg2, Operand(kSmiTagMask), ne);
+ b(eq, on_either_smi);
+}
+
+
void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
Register first,
Register second,