Improved performance of unary addition by avoiding runtime calls.
Fixed the handling of '>' and '<=' to use right-to-left conversion and left-to-right evaluation as specified by ECMA-262. Fixed a branch elimination bug on the ARM platform where incorrect code was generated because of overly aggressive branch elimination. Improved performance of code that repeatedly assigns the same function to the same property of different objects with the same map. Untangled DEBUG and ENABLE_DISASSEMBLER defines. The disassembler no longer expects DEBUG to be defined. Added platform-nullos.cc to serve as the basis for new platform implementations. git-svn-id: http://v8.googlecode.com/svn/trunk@9 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7276f14ca7
commit
769cc962a0
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
2008-08-06: Version 0.2.1 (130029)
|
||||
|
||||
Improved performance of unary addition by avoiding runtime calls.
|
||||
|
||||
Fixed the handling of '>' and '<=' to use right-to-left conversion
|
||||
and left-to-right evaluation as specified by ECMA-262.
|
||||
|
||||
Fixed a branch elimination bug on the ARM platform where incorrect
|
||||
code was generated because of overly aggressive branch
|
||||
elimination.
|
||||
|
||||
Improved performance of code that repeatedly assigns the same
|
||||
function to the same property of different objects with the same
|
||||
map.
|
||||
|
||||
Untangled DEBUG and ENABLE_DISASSEMBLER defines. The disassembler
|
||||
no longer expects DEBUG to be defined.
|
||||
|
||||
Added platform-nullos.cc to serve as the basis for new platform
|
||||
implementations.
|
||||
|
||||
|
||||
2008-07-30: Version 0.2.0 (129146)
|
||||
|
||||
Changed all text files to have native svn:eol-style.
|
||||
|
@ -233,6 +233,7 @@ PLATFORM_DEPENDENT_SOURCES = {
|
||||
'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc', 'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc', 'macro-assembler-ia32.cc', 'simulator-ia32.cc', 'stub-cache-ia32.cc'],
|
||||
'os:linux': ['platform-linux.cc'],
|
||||
'os:macos': ['platform-macos.cc'],
|
||||
'os:nullos': ['platform-nullos.cc'],
|
||||
'os:win32': ['platform-win32.cc']
|
||||
}
|
||||
|
||||
|
@ -2091,7 +2091,7 @@ bool v8::V8::Initialize() {
|
||||
|
||||
|
||||
const char* v8::V8::GetVersion() {
|
||||
return "0.2.0 (129146)";
|
||||
return "0.2.1 (130029)";
|
||||
}
|
||||
|
||||
|
||||
|
@ -711,12 +711,12 @@ void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
|
||||
}
|
||||
|
||||
|
||||
int Assembler::branch_offset(Label* L, Condition cond) {
|
||||
int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
|
||||
// if we emit an unconditional jump/call and if the current position is the
|
||||
// target of the unbound label, we can change the binding position of the
|
||||
// unbound label, thereby eliminating an unnessary jump
|
||||
bool can_eliminate = false;
|
||||
if (cond == al && FLAG_eliminate_jumps &&
|
||||
if (jump_elimination_allowed && FLAG_eliminate_jumps &&
|
||||
unbound_label_.is_linked() && binding_pos_ == pc_offset()) {
|
||||
can_eliminate = true;
|
||||
if (FLAG_print_jump_elimination) {
|
||||
|
@ -177,6 +177,31 @@ enum Condition {
|
||||
INLINE(Condition NegateCondition(Condition cc));
|
||||
|
||||
|
||||
// Corresponds to transposing the operands of a comparison.
|
||||
inline Condition ReverseCondition(Condition cc) {
|
||||
switch (cc) {
|
||||
case lo:
|
||||
return hi;
|
||||
case hi:
|
||||
return lo;
|
||||
case hs:
|
||||
return ls;
|
||||
case ls:
|
||||
return hs;
|
||||
case lt:
|
||||
return gt;
|
||||
case gt:
|
||||
return lt;
|
||||
case ge:
|
||||
return le;
|
||||
case le:
|
||||
return ge;
|
||||
default:
|
||||
return cc;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// The pc store offset may be 8 or 12 depending on the processor implementation.
|
||||
int PcStoreOffset();
|
||||
|
||||
@ -371,8 +396,8 @@ class Assembler : public Malloced {
|
||||
|
||||
// Returns the branch offset to the given label from the current code position
|
||||
// Links the label to the current position if it is still unbound
|
||||
// Manages the jump elimination optimization if necessary
|
||||
int branch_offset(Label* L, Condition cond);
|
||||
// Manages the jump elimination optimization if the second parameter is true.
|
||||
int branch_offset(Label* L, bool jump_elimination_allowed);
|
||||
|
||||
// Return the address in the constant pool of the code target address used by
|
||||
// the branch/call instruction at pc.
|
||||
@ -403,11 +428,13 @@ class Assembler : public Malloced {
|
||||
void bx(Register target, Condition cond = al); // v5 and above, plus v4t
|
||||
|
||||
// Convenience branch instructions using labels
|
||||
void b(Label* L, Condition cond = al) { b(branch_offset(L, cond), cond); }
|
||||
void b(Condition cond, Label* L) { b(branch_offset(L, cond), cond); }
|
||||
void bl(Label* L, Condition cond = al) { bl(branch_offset(L, cond), cond); }
|
||||
void bl(Condition cond, Label* L) { bl(branch_offset(L, cond), cond); }
|
||||
void blx(Label* L) { blx(branch_offset(L, al)); } // v5 and above
|
||||
void b(Label* L, Condition cond = al) {
|
||||
b(branch_offset(L, cond == al), cond);
|
||||
}
|
||||
void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
|
||||
void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
|
||||
void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
|
||||
void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
|
||||
|
||||
// Data-processing instructions
|
||||
void and_(Register dst, Register src1, const Operand& src2,
|
||||
|
@ -2018,6 +2018,12 @@ void Assembler::emit_farith(int b1, int b2, int i) {
|
||||
|
||||
void Assembler::RecordRelocInfo(RelocMode rmode, intptr_t data) {
|
||||
ASSERT(rmode != no_reloc);
|
||||
// Don't record external references unless the heap will be serialized.
|
||||
if (rmode == external_reference &&
|
||||
!Serializer::enabled() &&
|
||||
!FLAG_debug_code) {
|
||||
return;
|
||||
}
|
||||
RelocInfo rinfo(pc_, rmode, data);
|
||||
reloc_info_writer.Write(&rinfo);
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask) {
|
||||
// Implementation of RelocInfo
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
const char* RelocInfo::RelocModeName(RelocMode rmode) {
|
||||
switch (rmode) {
|
||||
case no_reloc:
|
||||
@ -435,8 +435,10 @@ const char* RelocInfo::RelocModeName(RelocMode rmode) {
|
||||
}
|
||||
return "unknown relocation type";
|
||||
}
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void RelocInfo::Print() {
|
||||
PrintF("%p %s", pc_, RelocModeName(rmode_));
|
||||
if (rmode_ == comment) {
|
||||
|
@ -268,11 +268,14 @@ class RelocInfo BASE_EMBEDDED {
|
||||
void patch_code_with_call(Address target, int guard_bytes);
|
||||
INLINE(bool is_call_instruction());
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
// Printing
|
||||
static const char* RelocModeName(RelocMode rmode);
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
#ifdef DEBUG
|
||||
// Debugging
|
||||
void Print();
|
||||
void Verify();
|
||||
static const char* RelocModeName(RelocMode rmode);
|
||||
#endif
|
||||
|
||||
static const int kCodeTargetMask = (1 << (last_code_enum + 1)) - 1;
|
||||
|
@ -78,17 +78,14 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
|
||||
__ sub(r1, r1, Operand(1), SetCC);
|
||||
__ b(ge, &loop);
|
||||
|
||||
// Get the function to call from the stack and get the code from it.
|
||||
// Get the function to call from the stack.
|
||||
__ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
|
||||
__ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
|
||||
// Call the function.
|
||||
Label return_site;
|
||||
__ RecordPosition(position);
|
||||
__ Call(r1);
|
||||
ParameterCount actual(r0);
|
||||
__ InvokeFunction(r1, actual, CALL_FUNCTION);
|
||||
__ bind(&return_site);
|
||||
|
||||
// Restore context from the frame and discard the function.
|
||||
@ -161,10 +158,11 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
|
||||
// Push the function and the receiver onto the stack.
|
||||
__ mov(r5, Operand(r1)); // change save order: function above receiver
|
||||
__ stm(db_w, sp, r2.bit() | r5.bit());
|
||||
__ push(r1);
|
||||
__ push(r2);
|
||||
|
||||
// Copy arguments to the stack in a loop.
|
||||
// r1: function
|
||||
// r3: argc
|
||||
// r4: argv, i.e. points to first arg
|
||||
Label loop, entry;
|
||||
@ -172,9 +170,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
||||
// r2 points past last arg.
|
||||
__ b(&entry);
|
||||
__ bind(&loop);
|
||||
__ ldr(r1, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter
|
||||
__ ldr(r1, MemOperand(r1)); // dereference handle
|
||||
__ push(r1); // push parameter
|
||||
__ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter
|
||||
__ ldr(r0, MemOperand(r0)); // dereference handle
|
||||
__ push(r0); // push parameter
|
||||
__ bind(&entry);
|
||||
__ cmp(r4, Operand(r2));
|
||||
__ b(ne, &loop);
|
||||
@ -194,9 +192,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
||||
__ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
|
||||
code_target);
|
||||
} else {
|
||||
__ mov(ip, Operand(r0));
|
||||
__ mov(r0, Operand(r3));
|
||||
__ Call(ip);
|
||||
ParameterCount actual(r3);
|
||||
__ InvokeFunction(r1, actual, CALL_FUNCTION);
|
||||
}
|
||||
|
||||
// Exit the JS frame and remove the parameters (except function), and return.
|
||||
|
@ -2033,7 +2033,14 @@ void ArmCodeGenerator::Comparison(Condition cc, bool strict) {
|
||||
ASSERT(!strict || cc == eq);
|
||||
|
||||
Label exit, smi;
|
||||
__ pop(r1);
|
||||
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
|
||||
if (cc == gt || cc == le) {
|
||||
cc = ReverseCondition(cc);
|
||||
__ mov(r1, Operand(r0));
|
||||
__ pop(r0);
|
||||
} else {
|
||||
__ pop(r1);
|
||||
}
|
||||
__ orr(r2, r0, Operand(r1));
|
||||
__ tst(r2, Operand(kSmiTagMask));
|
||||
__ b(eq, &smi);
|
||||
@ -2100,14 +2107,15 @@ class CallFunctionStub: public CodeStub {
|
||||
void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
Label slow;
|
||||
|
||||
// Push the number of arguments.
|
||||
masm->Push(Operand(argc_));
|
||||
// Flush the TOS cache
|
||||
masm->push(r0);
|
||||
|
||||
// Get the function to call from the stack.
|
||||
// function, receiver [, arguments], argc_
|
||||
// function, receiver [, arguments]
|
||||
masm->ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
|
||||
|
||||
// Check that the function is really a JavaScript function.
|
||||
// r1: pushed function (to be verified)
|
||||
masm->tst(r1, Operand(kSmiTagMask));
|
||||
masm->b(eq, &slow);
|
||||
// Get the map of the function object.
|
||||
@ -2117,15 +2125,13 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
masm->b(ne, &slow);
|
||||
|
||||
// Fast-case: Invoke the function now.
|
||||
masm->ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
masm->ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
masm->ldr(r1,
|
||||
MemOperand(r1, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
|
||||
masm->add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
masm->Jump(r1); // Callee will return to the original call site directly.
|
||||
// r1: pushed function
|
||||
ParameterCount actual(argc_);
|
||||
masm->InvokeFunction(r1, actual, JUMP_FUNCTION);
|
||||
|
||||
// Slow-case: Non-function called.
|
||||
masm->bind(&slow);
|
||||
masm->mov(r0, Operand(argc_)); // Setup the number of arguments.
|
||||
masm->InvokeBuiltin("CALL_NON_FUNCTION", 0, JUMP_JS);
|
||||
}
|
||||
|
||||
|
@ -2304,9 +2304,16 @@ void Ia32CodeGenerator::Comparison(Condition cc, bool strict) {
|
||||
// Strict only makes sense for equality comparisons.
|
||||
ASSERT(!strict || cc == equal);
|
||||
|
||||
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
|
||||
if (cc == greater || cc == less_equal) {
|
||||
cc = ReverseCondition(cc);
|
||||
__ pop(edx);
|
||||
__ pop(eax);
|
||||
} else {
|
||||
__ pop(eax);
|
||||
__ pop(edx);
|
||||
}
|
||||
ComparisonDeferred* deferred = new ComparisonDeferred(this, cc, strict);
|
||||
__ pop(eax);
|
||||
__ pop(edx);
|
||||
__ mov(ecx, Operand(eax));
|
||||
__ or_(ecx, Operand(edx));
|
||||
__ test(ecx, Immediate(kSmiTagMask));
|
||||
@ -4354,10 +4361,20 @@ void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
|
||||
__ mov(TOS, Factory::undefined_value());
|
||||
break;
|
||||
|
||||
case Token::ADD:
|
||||
case Token::ADD: {
|
||||
// Smi check.
|
||||
Label continue_label;
|
||||
__ pop(eax);
|
||||
__ test(eax, Immediate(kSmiTagMask));
|
||||
__ j(zero, &continue_label);
|
||||
|
||||
__ push(eax);
|
||||
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
|
||||
|
||||
__ bind(&continue_label);
|
||||
__ push(eax);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
48
src/debug.cc
48
src/debug.cc
@ -1742,9 +1742,7 @@ DebugMessageThread::~DebugMessageThread() {
|
||||
// The new copy of the event string is destroyed in Run().
|
||||
void DebugMessageThread::SendMessage(Vector<uint16_t> message) {
|
||||
Vector<uint16_t> message_copy = message.Clone();
|
||||
if (FLAG_log_debugger) {
|
||||
Logger::StringEvent("Put message on event message_queue.", "");
|
||||
}
|
||||
Logger::DebugTag("Put message on event message_queue.");
|
||||
message_queue_.Put(message_copy);
|
||||
message_received_->Signal();
|
||||
}
|
||||
@ -1801,9 +1799,7 @@ void DebugMessageThread::Run() {
|
||||
while (true) {
|
||||
// Wait and Get are paired so that semaphore count equals queue length.
|
||||
message_received_->Wait();
|
||||
if (FLAG_log_debugger) {
|
||||
Logger::StringEvent("Get message from event message_queue.", "");
|
||||
}
|
||||
Logger::DebugTag("Get message from event message_queue.");
|
||||
Vector<uint16_t> message = message_queue_.Get();
|
||||
if (message.length() > 0) {
|
||||
Debugger::SendMessage(message);
|
||||
@ -1867,11 +1863,7 @@ void DebugMessageThread::DebugEvent(v8::DebugEvent event,
|
||||
// Drain queue.
|
||||
while (!command_queue_.IsEmpty()) {
|
||||
command_received_->Wait();
|
||||
if (FLAG_log_debugger) {
|
||||
Logger::StringEvent(
|
||||
"Get command from command_queue, in drain queue loop.",
|
||||
"");
|
||||
}
|
||||
Logger::DebugTag("Get command from command_queue, in drain queue loop.");
|
||||
Vector<uint16_t> command = command_queue_.Get();
|
||||
// Support for sending a break command as just "break" instead of an
|
||||
// actual JSON break command.
|
||||
@ -1921,11 +1913,7 @@ void DebugMessageThread::DebugEvent(v8::DebugEvent event,
|
||||
// Wait for commands from the debugger.
|
||||
while (true) {
|
||||
command_received_->Wait();
|
||||
if (FLAG_log_debugger) {
|
||||
Logger::StringEvent(
|
||||
"Get command from command queue, in interactive loop.",
|
||||
"");
|
||||
}
|
||||
Logger::DebugTag("Get command from command queue, in interactive loop.");
|
||||
Vector<uint16_t> command = command_queue_.Get();
|
||||
ASSERT(!host_running_);
|
||||
if (!Debugger::debugger_active()) {
|
||||
@ -2002,9 +1990,7 @@ void DebugMessageThread::DebugEvent(v8::DebugEvent event,
|
||||
// The new copy of the command is destroyed in HandleCommand().
|
||||
void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) {
|
||||
Vector<uint16_t> command_copy = command.Clone();
|
||||
if (FLAG_log_debugger) {
|
||||
Logger::StringEvent("Put command on command_queue.", "");
|
||||
}
|
||||
Logger::DebugTag("Put command on command_queue.");
|
||||
command_queue_.Put(command_copy);
|
||||
// If not in a break schedule a break and send the "request queued" response.
|
||||
if (host_running_) {
|
||||
@ -2084,11 +2070,7 @@ bool LockingMessageQueue::IsEmpty() const {
|
||||
Vector<uint16_t> LockingMessageQueue::Get() {
|
||||
ScopedLock sl(lock_);
|
||||
Vector<uint16_t> result = queue_.Get();
|
||||
// Logging code for debugging debugger.
|
||||
if (FLAG_log_debugger) {
|
||||
LogQueueOperation("Get", result);
|
||||
}
|
||||
|
||||
Logger::DebugEvent("Get", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2096,10 +2078,7 @@ Vector<uint16_t> LockingMessageQueue::Get() {
|
||||
void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
|
||||
ScopedLock sl(lock_);
|
||||
queue_.Put(message);
|
||||
// Logging code for debugging debugger.
|
||||
if (FLAG_log_debugger) {
|
||||
LogQueueOperation("Put", message);
|
||||
}
|
||||
Logger::DebugEvent("Put", message);
|
||||
}
|
||||
|
||||
|
||||
@ -2109,17 +2088,4 @@ void LockingMessageQueue::Clear() {
|
||||
}
|
||||
|
||||
|
||||
void LockingMessageQueue::LogQueueOperation(const char* operation_name,
|
||||
Vector<uint16_t> parameter) {
|
||||
StringBuilder s(23+parameter.length()+strlen(operation_name) +1);
|
||||
s.AddFormatted("Time: %f15.3 %s ", OS::TimeCurrentMillis(), operation_name);
|
||||
for (int i = 0; i < parameter.length(); ++i) {
|
||||
s.AddCharacter(static_cast<char>(parameter[i]));
|
||||
}
|
||||
char* result_string = s.Finalize();
|
||||
Logger::StringEvent(result_string, "");
|
||||
DeleteArray(result_string);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -407,7 +407,7 @@ class MessageQueue BASE_EMBEDDED {
|
||||
// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
|
||||
// messages. The message data is not managed by LockingMessageQueue.
|
||||
// Pointers to the data are passed in and out. Implemented by adding a
|
||||
// Mutex to MessageQueue.
|
||||
// Mutex to MessageQueue. Includes logging of all puts and gets.
|
||||
class LockingMessageQueue BASE_EMBEDDED {
|
||||
public:
|
||||
explicit LockingMessageQueue(int size);
|
||||
@ -417,9 +417,6 @@ class LockingMessageQueue BASE_EMBEDDED {
|
||||
void Put(const Vector<uint16_t>& message);
|
||||
void Clear();
|
||||
private:
|
||||
// Logs a timestamp, operation name, and operation argument
|
||||
void LogQueueOperation(const char* operation_name,
|
||||
Vector<uint16_t> parameter);
|
||||
MessageQueue queue_;
|
||||
Mutex* lock_;
|
||||
DISALLOW_EVIL_CONSTRUCTORS(LockingMessageQueue);
|
||||
|
@ -224,9 +224,8 @@ static int DecodeIt(FILE* f,
|
||||
ASSERT(obj->IsSmi());
|
||||
// Get the STUB key and extract major and minor key.
|
||||
uint32_t key = Smi::cast(obj)->value();
|
||||
CodeStub::Major major_key = code->major_key();
|
||||
uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
|
||||
ASSERT(major_key == CodeStub::MajorKeyFromKey(key));
|
||||
ASSERT(code->major_key() == CodeStub::MajorKeyFromKey(key));
|
||||
out.AddFormatted(" (%s, %s, ",
|
||||
Code::Kind2String(kind),
|
||||
CodeStub::MajorName(code->major_key()));
|
||||
|
@ -111,7 +111,7 @@ class JavaScriptFrameConstants : public AllStatic {
|
||||
static const int kSavedRegistersOffset = +2 * kPointerSize;
|
||||
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
|
||||
|
||||
// PP-relative.
|
||||
// CallerSP-relative (aka PP-relative)
|
||||
static const int kParam0Offset = -2 * kPointerSize;
|
||||
static const int kReceiverOffset = -1 * kPointerSize;
|
||||
};
|
||||
|
@ -2420,7 +2420,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
|
||||
|
||||
// The new space size must be a power of two to support single-bit testing
|
||||
// for containment.
|
||||
semispace_size_ = NextPowerOf2(semispace_size_);
|
||||
semispace_size_ = RoundUpToPowerOf2(semispace_size_);
|
||||
initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
|
||||
young_generation_size_ = 2 * semispace_size_;
|
||||
|
||||
|
@ -985,15 +985,18 @@ class MarkingStack {
|
||||
|
||||
void clear_overflowed() { overflowed_ = false; }
|
||||
|
||||
void Push(HeapObject* p) {
|
||||
void Push(HeapObject* object) {
|
||||
ASSERT(!is_full());
|
||||
*(top_++) = p;
|
||||
CHECK(object->IsHeapObject());
|
||||
*(top_++) = object;
|
||||
if (is_full()) overflowed_ = true;
|
||||
}
|
||||
|
||||
HeapObject* Pop() {
|
||||
ASSERT(!is_empty());
|
||||
return *(--top_);
|
||||
HeapObject* object = *(--top_);
|
||||
CHECK(object->IsHeapObject());
|
||||
return object;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -340,7 +340,6 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
|
||||
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0: number of arguments
|
||||
// -- r1: receiver
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
@ -348,11 +347,7 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
Label miss, probe, done, global;
|
||||
|
||||
// Get the name of the function from the stack; 1 ~ receiver.
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ ldr(r2, MemOperand(ip, 1 * kPointerSize));
|
||||
|
||||
// Push the number of arguments on the stack to free r0.
|
||||
__ push(r0);
|
||||
__ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
@ -385,33 +380,20 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
__ cmp(r0, Operand(JS_FUNCTION_TYPE));
|
||||
__ b(ne, &miss);
|
||||
|
||||
// Restore the number of arguments.
|
||||
__ pop(r0);
|
||||
|
||||
// Patch the function on the stack; 1 ~ receiver.
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ str(r1, MemOperand(ip, 1 * kPointerSize));
|
||||
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Get the context and call code from the function.
|
||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
|
||||
|
||||
// Jump to the code.
|
||||
__ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ Jump(r1);
|
||||
// Invoke the function.
|
||||
ParameterCount actual(argc);
|
||||
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
|
||||
|
||||
// Global object access: Check access rights.
|
||||
__ bind(&global);
|
||||
__ CheckAccessGlobal(r1, r0, &miss);
|
||||
__ b(&probe);
|
||||
|
||||
// Cache miss: Restore number of arguments and receiver from stack
|
||||
// and jump to runtime.
|
||||
// Cache miss: Jump to runtime.
|
||||
__ bind(&miss);
|
||||
__ pop(r0);
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ ldr(r1, MemOperand(ip));
|
||||
Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
|
||||
}
|
||||
|
||||
@ -420,14 +402,13 @@ void CallIC::Generate(MacroAssembler* masm,
|
||||
int argc,
|
||||
const ExternalReference& f) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0: number of arguments
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
|
||||
// Get the receiver of the function from the stack into r1.
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ ldr(r1, MemOperand(ip, 0 * kPointerSize));
|
||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||
|
||||
__ mov(r0, Operand(argc)); // Setup number of arguments for EnterJSFrame.
|
||||
__ EnterJSFrame(0);
|
||||
|
||||
// Push the receiver and the name of the function.
|
||||
@ -442,25 +423,17 @@ void CallIC::Generate(MacroAssembler* masm,
|
||||
CEntryStub stub;
|
||||
__ CallStub(&stub);
|
||||
|
||||
// Move result to r1 and restore number of arguments.
|
||||
// Move result to r1.
|
||||
__ mov(r1, Operand(r0));
|
||||
__ ldr(r0, MemOperand(v8::internal::fp, // fp is shadowed by IC::fp
|
||||
JavaScriptFrameConstants::kArgsLengthOffset));
|
||||
|
||||
__ ExitJSFrame(DO_NOT_RETURN);
|
||||
|
||||
// Patch the function on the stack; 1 ~ receiver.
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ str(r1, MemOperand(ip, 1 * kPointerSize));
|
||||
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Get the context and call code from the function.
|
||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
|
||||
|
||||
// Jump to the code.
|
||||
__ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ Jump(r1);
|
||||
// Invoke the function.
|
||||
ParameterCount actual(argc);
|
||||
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
|
@ -503,9 +503,8 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
__ CheckAccessGlobal(edx, eax, &miss);
|
||||
__ jmp(&probe);
|
||||
|
||||
// Cache miss: Restore receiver from stack and jump to runtime.
|
||||
// Cache miss: Jump to runtime.
|
||||
__ bind(&miss);
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // 1 ~ return address
|
||||
Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
|
||||
}
|
||||
|
||||
|
31
src/log.cc
31
src/log.cc
@ -45,7 +45,6 @@ DEFINE_bool(log_all, false, "Log all events to the log file.");
|
||||
DEFINE_bool(log_api, false, "Log API events to the log file.");
|
||||
DEFINE_bool(log_code, false,
|
||||
"Log code events to the log file without profiling.");
|
||||
DEFINE_bool(log_debugger, false, "Log debugger internal messages.");
|
||||
DEFINE_bool(log_gc, false,
|
||||
"Log heap samples on garbage collection for the hp2ps tool.");
|
||||
DEFINE_bool(log_handles, false, "Log global handle events.");
|
||||
@ -564,6 +563,34 @@ void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
|
||||
}
|
||||
|
||||
|
||||
void Logger::DebugTag(const char* call_site_tag) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (logfile_ == NULL) return;
|
||||
ScopedLock sl(mutex_);
|
||||
fprintf(logfile_, "debug-tag,%s\n", call_site_tag);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
if (logfile_ == NULL) return;
|
||||
StringBuilder s(parameter.length() + 1);
|
||||
for (int i = 0; i < parameter.length(); ++i) {
|
||||
s.AddCharacter(static_cast<char>(parameter[i]));
|
||||
}
|
||||
char* parameter_string = s.Finalize();
|
||||
ScopedLock sl(mutex_);
|
||||
fprintf(logfile_,
|
||||
"debug-queue-event,%s,%15.3f,%s\n",
|
||||
event_type,
|
||||
OS::TimeCurrentMillis(),
|
||||
parameter_string);
|
||||
DeleteArray(parameter_string);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
void Logger::TickEvent(TickSample* sample, bool overflow) {
|
||||
if (logfile_ == NULL) return;
|
||||
@ -592,7 +619,7 @@ bool Logger::Setup() {
|
||||
|
||||
// Each of the individual log flags implies --log. Check after
|
||||
// checking --log-all and --prof in case they set --log-code.
|
||||
if (FLAG_log_api || FLAG_log_code || FLAG_log_debugger || FLAG_log_gc ||
|
||||
if (FLAG_log_api || FLAG_log_code || FLAG_log_gc ||
|
||||
FLAG_log_handles || FLAG_log_suspect) {
|
||||
FLAG_log = true;
|
||||
}
|
||||
|
@ -49,9 +49,6 @@ namespace v8 { namespace internal {
|
||||
// Log code (create, move, and delete) events to the logfile, default is off.
|
||||
// --log-code implies --log.
|
||||
//
|
||||
// --log-debugger
|
||||
// Log the internal activity of the debugger, to aid in debugging the debugger.
|
||||
//
|
||||
// --log-gc
|
||||
// Log GC heap samples after each GC that can be processed by hp2ps, default
|
||||
// is off. --log-gc implies --log.
|
||||
@ -135,6 +132,11 @@ class Logger {
|
||||
// object.
|
||||
static void SuspectReadEvent(String* name, String* obj);
|
||||
|
||||
// Emits an event when a message is put on or read from a debugging queue.
|
||||
// DebugTag lets us put a call-site specific label on the event.
|
||||
static void DebugTag(const char* call_site_tag);
|
||||
static void DebugEvent(const char* event_type, Vector<uint16_t> parameter);
|
||||
|
||||
|
||||
// ==== Events logged by --log-api. ====
|
||||
static void ApiNamedSecurityCheck(Object* key);
|
||||
|
@ -364,6 +364,95 @@ void MacroAssembler::ExitJSFrame(ExitJSFlag flag) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
Handle<Code> code_constant,
|
||||
Register code_reg,
|
||||
Label* done,
|
||||
InvokeFlag flag) {
|
||||
if (actual.is_immediate()) {
|
||||
mov(r0, Operand(actual.immediate())); // Push the number of arguments.
|
||||
} else {
|
||||
if (!actual.reg().is(r0)) {
|
||||
mov(r0, Operand(actual.reg()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokeCode(Register code,
|
||||
const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
InvokeFlag flag) {
|
||||
Label done;
|
||||
|
||||
InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
|
||||
if (flag == CALL_FUNCTION) {
|
||||
Call(code);
|
||||
} else {
|
||||
ASSERT(flag == JUMP_FUNCTION);
|
||||
Jump(code);
|
||||
}
|
||||
|
||||
// Continue here if InvokePrologue does handle the invocation due to
|
||||
// mismatched parameter counts.
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokeCode(Handle<Code> code,
|
||||
const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
RelocMode rmode,
|
||||
InvokeFlag flag) {
|
||||
Label done;
|
||||
|
||||
InvokePrologue(expected, actual, code, no_reg, &done, flag);
|
||||
if (flag == CALL_FUNCTION) {
|
||||
Call(code, rmode);
|
||||
} else {
|
||||
Jump(code, rmode);
|
||||
}
|
||||
|
||||
// Continue here if InvokePrologue does handle the invocation due to
|
||||
// mismatched parameter counts.
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokeFunction(Register fun,
|
||||
const ParameterCount& actual,
|
||||
InvokeFlag flag) {
|
||||
// Contract with called JS functions requires that function is passed in r1.
|
||||
ASSERT(fun.is(r1));
|
||||
|
||||
Register code_reg = r3;
|
||||
Register expected_reg = r2;
|
||||
|
||||
// Make sure that the code and expected registers do not collide with the
|
||||
// actual register being passed in.
|
||||
if (actual.is_reg()) {
|
||||
if (actual.reg().is(code_reg)) {
|
||||
code_reg = r4;
|
||||
} else if (actual.reg().is(expected_reg)) {
|
||||
expected_reg = r4;
|
||||
}
|
||||
}
|
||||
|
||||
ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
ldr(expected_reg,
|
||||
FieldMemOperand(code_reg,
|
||||
SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
ldr(code_reg,
|
||||
MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
|
||||
add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
|
||||
ParameterCount expected(expected_reg);
|
||||
InvokeCode(code_reg, expected, actual, flag);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
|
||||
ASSERT((regs & ~kJSCallerSaved) == 0);
|
||||
// Copy the content of registers to memory location.
|
||||
|
@ -39,6 +39,11 @@ extern Register pp; // parameter pointer
|
||||
|
||||
|
||||
// Helper types to make boolean flag easier to read at call-site.
|
||||
enum InvokeFlag {
|
||||
CALL_FUNCTION,
|
||||
JUMP_FUNCTION
|
||||
};
|
||||
|
||||
enum InvokeJSFlags {
|
||||
CALL_JS,
|
||||
JUMP_JS
|
||||
@ -103,6 +108,35 @@ class MacroAssembler: public Assembler {
|
||||
void Pop(Register dst);
|
||||
void Pop(const MemOperand& dst);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// JavaScript invokes
|
||||
|
||||
// Helper functions for generating invokes.
|
||||
void InvokePrologue(const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
Handle<Code> code_constant,
|
||||
Register code_reg,
|
||||
Label* done,
|
||||
InvokeFlag flag);
|
||||
|
||||
// Invoke the JavaScript function code by either calling or jumping.
|
||||
void InvokeCode(Register code,
|
||||
const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
InvokeFlag flag);
|
||||
|
||||
void InvokeCode(Handle<Code> code,
|
||||
const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
RelocMode rmode,
|
||||
InvokeFlag flag);
|
||||
|
||||
// Invoke the JavaScript function in the given register. Changes the
|
||||
// current context to the context in the function before invoking.
|
||||
void InvokeFunction(Register function,
|
||||
const ParameterCount& actual,
|
||||
InvokeFlag flag);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Debugger Support
|
||||
|
||||
|
@ -86,6 +86,7 @@ macro IS_SCRIPT(arg) = (%ClassOf(arg) === 'Script');
|
||||
|
||||
# 'Inline' macros
|
||||
# (Make sure arg is evaluated only once via %IS_VAR)
|
||||
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
|
||||
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
|
||||
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInt32(arg));
|
||||
|
||||
|
@ -270,12 +270,6 @@ class MarkingVisitor : public ObjectVisitor {
|
||||
}
|
||||
|
||||
private:
|
||||
// Mark obj if needed.
|
||||
void MarkObject(Object* obj) {
|
||||
if (!obj->IsHeapObject()) return;
|
||||
MarkCompactCollector::MarkObject(HeapObject::cast(obj));
|
||||
}
|
||||
|
||||
// Mark object pointed to by p.
|
||||
void MarkObjectByPointer(Object** p) {
|
||||
Object* obj = *p;
|
||||
|
12
src/math.js
12
src/math.js
@ -46,7 +46,13 @@ $Math.__proto__ = global.Object.prototype;
|
||||
function $Math_random() { return %Math_random(0); }
|
||||
%AddProperty($Math, "random", $Math_random, DONT_ENUM);
|
||||
|
||||
function $Math_abs(x) { return %Math_abs(ToNumber(x)); }
|
||||
function $Math_abs(x) {
|
||||
if (%_IsSmi(x)) {
|
||||
return x >= 0 ? x : -x;
|
||||
} else {
|
||||
return %Math_abs(ToNumber(x));
|
||||
}
|
||||
}
|
||||
%AddProperty($Math, "abs", $Math_abs, DONT_ENUM);
|
||||
|
||||
function $Math_acos(x) { return %Math_acos(ToNumber(x)); }
|
||||
@ -95,7 +101,7 @@ function $Math_max(arg1, arg2) { // length == 2
|
||||
var r = -$Infinity;
|
||||
for (var i = %_ArgumentsLength() - 1; i >= 0; --i) {
|
||||
var n = ToNumber(%_Arguments(i));
|
||||
if (%NumberIsNaN(n)) return n;
|
||||
if (NUMBER_IS_NAN(n)) return n;
|
||||
// Make sure +0 is consider greater than -0.
|
||||
if (n > r || (n === 0 && r === 0 && (1 / n) > (1 / r))) r = n;
|
||||
}
|
||||
@ -107,7 +113,7 @@ function $Math_min(arg1, arg2) { // length == 2
|
||||
var r = $Infinity;
|
||||
for (var i = %_ArgumentsLength() - 1; i >= 0; --i) {
|
||||
var n = ToNumber(%_Arguments(i));
|
||||
if (%NumberIsNaN(n)) return n;
|
||||
if (NUMBER_IS_NAN(n)) return n;
|
||||
// Make sure -0 is consider less than +0.
|
||||
if (n < r || (n === 0 && r === 0 && (1 / n) < (1 / r))) r = n;
|
||||
}
|
||||
|
@ -592,22 +592,6 @@ void Oddball::OddballVerify() {
|
||||
}
|
||||
|
||||
|
||||
const char* Code::Kind2String(Kind kind) {
|
||||
switch (kind) {
|
||||
case FUNCTION: return "FUNCTION";
|
||||
case STUB: return "STUB";
|
||||
case BUILTIN: return "BUILTIN";
|
||||
case LOAD_IC: return "LOAD_IC";
|
||||
case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
|
||||
case STORE_IC: return "STORE_IC";
|
||||
case KEYED_STORE_IC: return "KEYED_STORE_IC";
|
||||
case CALL_IC: return "CALL_IC";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void Code::CodePrint() {
|
||||
HeapObject::PrintHeader("Code");
|
||||
PrintF("kind = %s", Kind2String(kind()));
|
||||
@ -995,6 +979,27 @@ void DescriptorArray::PrintDescriptors() {
|
||||
}
|
||||
|
||||
|
||||
bool DescriptorArray::IsSortedNoDuplicates() {
|
||||
String* current_key = NULL;
|
||||
uint32_t current = 0;
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
String* key = r.GetKey();
|
||||
if (key == current_key) {
|
||||
PrintDescriptors();
|
||||
return false;
|
||||
}
|
||||
current_key = key;
|
||||
uint32_t hash = r.GetKey()->Hash();
|
||||
if (hash < current) {
|
||||
PrintDescriptors();
|
||||
return false;
|
||||
}
|
||||
current = hash;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
128
src/objects.cc
128
src/objects.cc
@ -139,6 +139,19 @@ void Object::Lookup(String* name, LookupResult* result) {
|
||||
} else if (IsBoolean()) {
|
||||
holder = global_context->boolean_function()->instance_prototype();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// Used to track outstanding bug #1308895.
|
||||
// TODO(1308895) Remove when bug is fixed.
|
||||
if (holder == NULL) {
|
||||
PrintF("\nName being looked up: ");
|
||||
name->Print();
|
||||
PrintF("\nThis (object name is looked up in: ");
|
||||
this->Print();
|
||||
if (IsScript()) {
|
||||
PrintF("IsScript() returns true.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ASSERT(holder != NULL); // cannot handle null or undefined.
|
||||
JSObject::cast(holder)->Lookup(name, result);
|
||||
}
|
||||
@ -960,13 +973,29 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
return AddSlowProperty(name, value, attributes);
|
||||
}
|
||||
|
||||
// Replace a CONSTANT_TRANSITION flag with a transition.
|
||||
// Do this by removing it, and the standard code for adding a map transition
|
||||
// will then run.
|
||||
DescriptorArray* old_descriptors = map()->instance_descriptors();
|
||||
int old_name_index = old_descriptors->Search(name);
|
||||
bool constant_transition = false; // Only used in assertions.
|
||||
if (old_name_index != DescriptorArray::kNotFound && CONSTANT_TRANSITION ==
|
||||
PropertyDetails(old_descriptors->GetDetails(old_name_index)).type()) {
|
||||
constant_transition = true;
|
||||
Object* r = old_descriptors->CopyRemove(name);
|
||||
if (r->IsFailure()) return r;
|
||||
old_descriptors = DescriptorArray::cast(r);
|
||||
map()->set_instance_descriptors(old_descriptors);
|
||||
old_name_index = DescriptorArray::kNotFound;
|
||||
}
|
||||
|
||||
// Compute the new index for new field.
|
||||
int index = map()->NextFreePropertyIndex();
|
||||
|
||||
// Allocate new instance descriptors with (name, index) added
|
||||
FieldDescriptor fd(name, index, attributes);
|
||||
FieldDescriptor new_field(name, index, attributes);
|
||||
Object* new_descriptors =
|
||||
map()->instance_descriptors()->CopyInsert(&fd, true);
|
||||
map()->instance_descriptors()->CopyInsert(&new_field, true);
|
||||
if (new_descriptors->IsFailure()) return new_descriptors;
|
||||
|
||||
// Only allow map transition if the object's map is NOT equal to the
|
||||
@ -974,6 +1003,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
bool allow_map_transition =
|
||||
!map()->instance_descriptors()->Contains(name) &&
|
||||
(Top::context()->global_context()->object_function()->map() != map());
|
||||
ASSERT(allow_map_transition || !constant_transition);
|
||||
|
||||
if (map()->unused_property_fields() > 0) {
|
||||
ASSERT(index < properties()->length());
|
||||
@ -1055,8 +1085,34 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
|
||||
|
||||
DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
|
||||
Map::cast(new_map)->set_instance_descriptors(descriptors);
|
||||
Map* old_map = map();
|
||||
set_map(Map::cast(new_map));
|
||||
|
||||
// If the old map is the global object map (from new Object()),
|
||||
// then transitions are not added to it, so we are done.
|
||||
if (old_map == Top::context()->global_context()->object_function()->map()) {
|
||||
return function;
|
||||
}
|
||||
|
||||
// Do not add CONSTANT_TRANSITIONS to global objects
|
||||
if (IsGlobalObject()) {
|
||||
return function;
|
||||
}
|
||||
|
||||
// Add a CONSTANT_TRANSITION descriptor to the old map,
|
||||
// so future assignments to this property on other objects
|
||||
// of the same type will create a normal field, not a constant function.
|
||||
// Don't do this for special properties, with non-trival attributes.
|
||||
if (attributes != NONE) {
|
||||
return function;
|
||||
}
|
||||
ConstTransitionDescriptor mark(name);
|
||||
new_descriptors = old_map->instance_descriptors()->CopyInsert(&mark, false);
|
||||
if (new_descriptors->IsFailure()) {
|
||||
return new_descriptors;
|
||||
}
|
||||
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
@ -1356,7 +1412,7 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
|
||||
}
|
||||
} else {
|
||||
int entry = property_dictionary()->FindStringEntry(name);
|
||||
if (entry != -1) {
|
||||
if (entry != DescriptorArray::kNotFound) {
|
||||
// Make sure to disallow caching for uninitialized constants
|
||||
// found in the dictionary-mode objects.
|
||||
if (property_dictionary()->ValueAt(entry)->IsTheHole()) {
|
||||
@ -1494,7 +1550,12 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
case INTERCEPTOR:
|
||||
return SetPropertyWithInterceptor(name, value, attributes);
|
||||
case CONSTANT_TRANSITION:
|
||||
break;
|
||||
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
|
||||
// if the value is a function.
|
||||
// AddProperty has been extended to do this, in this case.
|
||||
return AddFastProperty(name, value, attributes);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1731,6 +1792,7 @@ Object* JSObject::NormalizeProperties() {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(details.IsTransition());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2631,18 +2693,33 @@ Object* DescriptorArray::CopyReplace(String* name,
|
||||
}
|
||||
|
||||
|
||||
bool DescriptorArray::IsSortedNoDuplicates() {
|
||||
String* current_key = NULL;
|
||||
uint32_t current = 0;
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
String* key = r.GetKey();
|
||||
if (key == current_key) return false;
|
||||
current_key = key;
|
||||
uint32_t hash = r.GetKey()->Hash();
|
||||
if (hash < current) return false;
|
||||
current = hash;
|
||||
Object* DescriptorArray::CopyRemove(String* name) {
|
||||
if (!name->IsSymbol()) {
|
||||
Object* result = Heap::LookupSymbol(name);
|
||||
if (result->IsFailure()) return result;
|
||||
name = String::cast(result);
|
||||
}
|
||||
return true;
|
||||
ASSERT(name->IsSymbol());
|
||||
Object* result = Allocate(number_of_descriptors() - 1);
|
||||
if (result->IsFailure()) return result;
|
||||
DescriptorArray* new_descriptors = DescriptorArray::cast(result);
|
||||
|
||||
// Set the enumeration index in the descriptors and set the enumeration index
|
||||
// in the result.
|
||||
new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
|
||||
|
||||
// Write the old content and the descriptor information
|
||||
DescriptorWriter w(new_descriptors);
|
||||
DescriptorReader r(this);
|
||||
while (!r.eos()) {
|
||||
if (r.GetKey() != name) { // Both are symbols; object identity suffices.
|
||||
w.WriteFrom(&r);
|
||||
}
|
||||
r.advance();
|
||||
}
|
||||
ASSERT(w.eos());
|
||||
|
||||
return new_descriptors;
|
||||
}
|
||||
|
||||
|
||||
@ -3990,6 +4067,25 @@ int Code::SourceStatementPosition(Address pc) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
// Identify kind of code.
|
||||
const char* Code::Kind2String(Kind kind) {
|
||||
switch (kind) {
|
||||
case FUNCTION: return "FUNCTION";
|
||||
case STUB: return "STUB";
|
||||
case BUILTIN: return "BUILTIN";
|
||||
case LOAD_IC: return "LOAD_IC";
|
||||
case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
|
||||
case STORE_IC: return "STORE_IC";
|
||||
case KEYED_STORE_IC: return "KEYED_STORE_IC";
|
||||
case CALL_IC: return "CALL_IC";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
|
||||
|
||||
void JSObject::SetFastElements(FixedArray* elems) {
|
||||
#ifdef DEBUG
|
||||
// Check the provided array is filled with the_hole.
|
||||
@ -5193,7 +5289,7 @@ void HashTable<prefix_size, element_size>::IterateElements(ObjectVisitor* v) {
|
||||
|
||||
template<int prefix_size, int element_size>
|
||||
Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
|
||||
int capacity = NextPowerOf2(at_least_space_for);
|
||||
int capacity = RoundUpToPowerOf2(at_least_space_for);
|
||||
if (capacity < 4) capacity = 4; // Guarantee min capacity.
|
||||
Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
|
||||
if (!obj->IsFailure()) {
|
||||
|
@ -96,8 +96,10 @@ enum PropertyAttributes {
|
||||
READ_ONLY = v8::ReadOnly,
|
||||
DONT_ENUM = v8::DontEnum,
|
||||
DONT_DELETE = v8::DontDelete,
|
||||
INTERCEPTED = 1 << 3,
|
||||
ABSENT = 16 // Used in runtime to indicate a property is absent.
|
||||
// ABSENT can never be stored in or returned from a descriptor's attributes
|
||||
// bitfield. It is only used as a return value meaning the attributes of
|
||||
// a non-existent property.
|
||||
};
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
@ -1133,6 +1135,8 @@ class JSObject: public HeapObject {
|
||||
PropertyAttributes attributes);
|
||||
Object* IgnoreAttributesAndSetLocalProperty(String* key,
|
||||
Object* value);
|
||||
|
||||
// Sets a property that currently has lazy loading.
|
||||
Object* SetLazyProperty(LookupResult* result,
|
||||
String* name,
|
||||
Object* value,
|
||||
@ -1284,6 +1288,11 @@ class JSObject: public HeapObject {
|
||||
Object* value);
|
||||
|
||||
// Add a constant function property to a fast-case object.
|
||||
// This leaves a CONSTANT_TRANSITION in the old map, and
|
||||
// if it is called on a second object with this map, a
|
||||
// normal property is added instead, with a map transition.
|
||||
// This avoids the creation of many maps with the same constant
|
||||
// function, all orphaned.
|
||||
Object* AddConstantFunctionProperty(String* name,
|
||||
JSFunction* function,
|
||||
PropertyAttributes attributes);
|
||||
@ -1551,12 +1560,13 @@ class DescriptorArray: public FixedArray {
|
||||
// of the named property, but preserve its enumeration index.
|
||||
Object* CopyReplace(String* name, int index, PropertyAttributes attributes);
|
||||
|
||||
// Copy the descriptor array, removing the property index and attributes
|
||||
// of the named property.
|
||||
Object* CopyRemove(String* name);
|
||||
|
||||
// Sort the instance descriptors by the hash codes of their keys.
|
||||
void Sort();
|
||||
|
||||
// Is the descriptor array sorted and without duplicates?
|
||||
bool IsSortedNoDuplicates();
|
||||
|
||||
// Search the instance descriptors for given name.
|
||||
inline int Search(String* name);
|
||||
|
||||
@ -1599,6 +1609,9 @@ class DescriptorArray: public FixedArray {
|
||||
#ifdef DEBUG
|
||||
// Print all the descriptors.
|
||||
void PrintDescriptors();
|
||||
|
||||
// Is the descriptor array sorted and without duplicates?
|
||||
bool IsSortedNoDuplicates();
|
||||
#endif
|
||||
|
||||
// The maximum number of descriptors we want in a descriptor array (should
|
||||
@ -2014,9 +2027,10 @@ class Code: public HeapObject {
|
||||
IC_TARGET_IS_OBJECT
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
// Printing
|
||||
static const char* Kind2String(Kind kind);
|
||||
#endif
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
|
||||
// [instruction_size]: Size of the native instructions
|
||||
inline int instruction_size();
|
||||
@ -2511,8 +2525,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
|
||||
static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
|
||||
static const int kDebugInfoOffset = kFunctionTokenPositionOffset + kIntSize;
|
||||
static const int kAccessAttributesOffset = kDebugInfoOffset + kPointerSize;
|
||||
static const int kSize = kAccessAttributesOffset + kPointerSize;
|
||||
static const int kSize = kDebugInfoOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
|
||||
|
@ -2174,6 +2174,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber()) {
|
||||
double x_val = x->AsLiteral()->handle()->Number();
|
||||
switch (op) {
|
||||
case Token::ADD:
|
||||
return x;
|
||||
case Token::SUB:
|
||||
return NewNumberLiteral(-x_val);
|
||||
case Token::BIT_NOT:
|
||||
|
421
src/platform-nullos.cc
Normal file
421
src/platform-nullos.cc
Normal file
@ -0,0 +1,421 @@
|
||||
// Copyright 2006-2008 Google Inc. 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.
|
||||
|
||||
// Platform specific code for NULLOS goes here
|
||||
|
||||
// Minimal include to get access to abort, fprintf and friends for bootstrapping
|
||||
// messages.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
// Give V8 the opportunity to override the default ceil behaviour.
|
||||
double ceiling(double x) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Initialize OS class early in the V8 startup.
|
||||
void OS::Setup() {
|
||||
// Seed the random number generator.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Returns the accumulated user time for thread.
|
||||
int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
|
||||
UNIMPLEMENTED();
|
||||
*secs = 0;
|
||||
*usecs = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns current time as the number of milliseconds since
|
||||
// 00:00:00 UTC, January 1, 1970.
|
||||
double OS::TimeCurrentMillis() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns ticks in microsecond resolution.
|
||||
int64_t OS::Ticks() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns a string identifying the current timezone taking into
|
||||
// account daylight saving.
|
||||
char* OS::LocalTimezone(double time) {
|
||||
UNIMPLEMENTED();
|
||||
return "<none>";
|
||||
}
|
||||
|
||||
|
||||
// Returns the daylight savings offset in milliseconds for the given time.
|
||||
double OS::DaylightSavingsOffset(double time) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the local time offset in milliseconds east of UTC without
|
||||
// taking daylight savings time into account.
|
||||
double OS::LocalTimeOffset() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Print (debug) message to console.
|
||||
void OS::Print(const char* format, ...) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
// Print (debug) message to console.
|
||||
void OS::VPrint(const char* format, va_list args) {
|
||||
// Minimalistic implementation for bootstrapping.
|
||||
vfprintf(stdout, format, args);
|
||||
}
|
||||
|
||||
|
||||
// Print error message to console.
|
||||
void OS::PrintError(const char* format, ...) {
|
||||
// Minimalistic implementation for bootstrapping.
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VPrintError(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
// Print error message to console.
|
||||
void OS::VPrintError(const char* format, va_list args) {
|
||||
// Minimalistic implementation for bootstrapping.
|
||||
vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
|
||||
int OS::SNPrintF(char* str, size_t size, const char* format, ...) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int OS::VSNPrintF(char* str, size_t size, const char* format, va_list args) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double OS::nan_value() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool OS::IsOutsideAllocatedSpace(void* address) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t OS::AllocateAlignment() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void* OS::Allocate(const size_t requested,
|
||||
size_t* allocated,
|
||||
bool executable) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void OS::Free(void* buf, const size_t length) {
|
||||
// TODO(1240712): potential system call return value which is ignored here.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void OS::Sleep(int milliseconds) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void OS::Abort() {
|
||||
// Minimalistic implementation for bootstrapping.
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void OS::DebugBreak() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
|
||||
void* initial) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void OS::LogSharedLibraryAddresses() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
VirtualMemory::VirtualMemory(size_t size, void* address_hint) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
VirtualMemory::~VirtualMemory() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
bool VirtualMemory::IsReserved() {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool VirtualMemory::Uncommit(void* address, size_t size) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class ThreadHandle::PlatformData : public Malloced {
|
||||
public:
|
||||
explicit PlatformData(ThreadHandle::Kind kind) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void* pd_data_;
|
||||
};
|
||||
|
||||
|
||||
ThreadHandle::ThreadHandle(Kind kind) {
|
||||
UNIMPLEMENTED();
|
||||
// Shared setup follows.
|
||||
data_ = new PlatformData(kind);
|
||||
}
|
||||
|
||||
|
||||
void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
ThreadHandle::~ThreadHandle() {
|
||||
UNIMPLEMENTED();
|
||||
// Shared tear down follows.
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadHandle::IsSelf() const {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadHandle::IsValid() const {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Thread::Start() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Thread::Join() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
|
||||
UNIMPLEMENTED();
|
||||
return static_cast<LocalStorageKey>(0);
|
||||
}
|
||||
|
||||
|
||||
void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void* Thread::GetThreadLocal(LocalStorageKey key) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void Thread::YieldCPU() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
class NullMutex : public Mutex {
|
||||
public:
|
||||
NullMutex() : data_(NULL) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual ~NullMutex() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual int Lock() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int Unlock() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void* data_;
|
||||
};
|
||||
|
||||
|
||||
Mutex* OS::CreateMutex() {
|
||||
UNIMPLEMENTED();
|
||||
return new NullMutex();
|
||||
}
|
||||
|
||||
|
||||
class NullSemaphore : public Semaphore {
|
||||
public:
|
||||
explicit NullSemaphore(int count) : data_(NULL) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual ~NullSemaphore() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual void Wait() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual void Signal() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
private:
|
||||
void* data_;
|
||||
};
|
||||
|
||||
|
||||
Semaphore* OS::CreateSemaphore(int count) {
|
||||
UNIMPLEMENTED();
|
||||
return new NullSemaphore(count);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
|
||||
class ProfileSampler::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ProfileSampler::ProfileSampler(int interval) {
|
||||
UNIMPLEMENTED();
|
||||
// Shared setup follows.
|
||||
data_ = new PlatformData();
|
||||
interval_ = interval;
|
||||
active_ = false;
|
||||
}
|
||||
|
||||
|
||||
ProfileSampler::~ProfileSampler() {
|
||||
UNIMPLEMENTED();
|
||||
// Shared tear down follows.
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
void ProfileSampler::Start() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void ProfileSampler::Stop() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
#endif // ENABLE_LOGGING_AND_PROFILING
|
||||
|
||||
} } // namespace v8::internal
|
@ -690,22 +690,30 @@ bool OS::IsOutsideAllocatedSpace(void* pointer) {
|
||||
}
|
||||
|
||||
|
||||
// Get the system's page size used by VirtualAlloc().
|
||||
// Get the system's page size used by VirtualAlloc() or the next power
|
||||
// of two. The reason for always returning a power of two is that the
|
||||
// rounding up in OS::Allocate expects that.
|
||||
static size_t GetPageSize() {
|
||||
static size_t page_size = 0;
|
||||
if (page_size == 0) {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
page_size = info.dwPageSize;
|
||||
page_size = RoundUpToPowerOf2(info.dwPageSize);
|
||||
}
|
||||
return page_size;
|
||||
}
|
||||
|
||||
|
||||
// The allocation alignment is the guaranteed alignment for
|
||||
// VirtualAlloc'ed blocks of memory.
|
||||
size_t OS::AllocateAlignment() {
|
||||
// See also http://blogs.msdn.com/oldnewthing/archive/2003/10/08/55239.aspx
|
||||
const size_t kWindowsVirtualAllocAlignment = 64*1024;
|
||||
return kWindowsVirtualAllocAlignment;
|
||||
static size_t allocate_alignment = 0;
|
||||
if (allocate_alignment == 0) {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
allocate_alignment = info.dwAllocationGranularity;
|
||||
}
|
||||
return allocate_alignment;
|
||||
}
|
||||
|
||||
|
||||
@ -717,7 +725,7 @@ void* OS::Allocate(const size_t requested,
|
||||
|
||||
// Windows XP SP2 allows Data Excution Prevention (DEP).
|
||||
int prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
LPVOID mbase = VirtualAlloc(NULL, requested, MEM_COMMIT | MEM_RESERVE, prot);
|
||||
LPVOID mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);
|
||||
if (mbase == NULL) {
|
||||
LOG(StringEvent("OS::Allocate", "VirtualAlloc failed"));
|
||||
return NULL;
|
||||
|
@ -456,17 +456,7 @@ void PrettyPrinter::Print(const char* format, ...) {
|
||||
int n = OS::VSNPrintF(output_ + pos_, available, format, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
// Return value from VSNPrintF is not portable. On linux the return value
|
||||
// is the number of characters which would have been written to the string
|
||||
// if enough space had been available. On windows it returns -1 if the
|
||||
// result is truncated but does not indicate the required buffer size.
|
||||
#ifdef WIN32
|
||||
if (n <= 0) n = available;
|
||||
#else
|
||||
CHECK_GE(n, 0); // no errors
|
||||
#endif
|
||||
|
||||
if (n < available) {
|
||||
if (n >= 0) {
|
||||
// there was enough space - we are done
|
||||
pos_ += n;
|
||||
return;
|
||||
@ -474,8 +464,6 @@ void PrettyPrinter::Print(const char* format, ...) {
|
||||
// there was not enough space - allocate more and try again
|
||||
const int slack = 32;
|
||||
int new_size = size_ + (size_ >> 1) + slack;
|
||||
if (new_size < size_ + n)
|
||||
new_size = size_ + n + slack;
|
||||
char* new_output = NewArray<char>(new_size);
|
||||
memcpy(new_output, output_, pos_);
|
||||
DeleteArray(output_);
|
||||
|
@ -108,7 +108,11 @@ class MapTransitionDescriptor: public Descriptor {
|
||||
: Descriptor(key, map, attributes, MAP_TRANSITION) { }
|
||||
};
|
||||
|
||||
|
||||
// Marks a field name in a map so that adding the field is guaranteed
|
||||
// to create a FIELD descriptor in the new map. Used after adding
|
||||
// a constant function the first time, creating a CONSTANT_FUNCTION
|
||||
// descriptor in the new map. This avoids creating multiple maps with
|
||||
// the same CONSTANT_FUNCTION field.
|
||||
class ConstTransitionDescriptor: public Descriptor {
|
||||
public:
|
||||
explicit ConstTransitionDescriptor(String* key)
|
||||
|
@ -3232,20 +3232,6 @@ static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Object* Runtime_NumberIsNaN(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(value, args[0]);
|
||||
if (isnan(value)) {
|
||||
return Heap::true_value();
|
||||
} else {
|
||||
return Heap::false_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberIsFinite(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
@ -3282,20 +3268,6 @@ static Object* Runtime_NumberNaN(Arguments) {
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberNegativeInfinity(Arguments) {
|
||||
NoHandleAllocation ha;
|
||||
|
||||
return Heap::negative_infinity_value();
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberPositiveInfinity(Arguments) {
|
||||
NoHandleAllocation ha;
|
||||
|
||||
return Heap::infinity_value();
|
||||
}
|
||||
|
||||
|
||||
static Object* EvalContext() {
|
||||
// The topmost JS frame belongs to the eval function which called
|
||||
// the CompileString runtime function. We need to unwind one level
|
||||
|
@ -107,9 +107,6 @@ namespace v8 { namespace internal {
|
||||
F(NumberShr, 2) \
|
||||
F(NumberSar, 2) \
|
||||
\
|
||||
F(NumberIsNaN, 1) \
|
||||
F(NumberIsFinite, 1) \
|
||||
\
|
||||
/* Comparisons */ \
|
||||
F(ObjectEquals, 2) \
|
||||
F(NumberEquals, 2) \
|
||||
@ -179,11 +176,10 @@ namespace v8 { namespace internal {
|
||||
F(DateDaylightSavingsOffset, 1) \
|
||||
\
|
||||
/* Numbers */ \
|
||||
F(NumberIsFinite, 1) \
|
||||
F(NumberMaxValue, 1) \
|
||||
F(NumberMinValue, 1) \
|
||||
F(NumberNaN, 1) \
|
||||
F(NumberNegativeInfinity, 1) \
|
||||
F(NumberPositiveInfinity, 1) \
|
||||
\
|
||||
/* Globals */ \
|
||||
F(CompileString, 2) \
|
||||
|
@ -428,7 +428,7 @@ function ToBoolean(x) {
|
||||
if (IS_BOOLEAN(x)) return x;
|
||||
if (IS_STRING(x)) return x.length != 0;
|
||||
if (x == null) return false;
|
||||
if (IS_NUMBER(x)) return !((x == 0) || %NumberIsNaN(x));
|
||||
if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -452,6 +452,7 @@ function ToInteger(x) {
|
||||
|
||||
// ECMA-262, section 9.6, page 34.
|
||||
function ToUint32(x) {
|
||||
if (%_IsSmi(x) && x >= 0) return x;
|
||||
return %NumberToJSUint32(ToNumber(x));
|
||||
};
|
||||
|
||||
|
@ -59,7 +59,9 @@ class Debugger {
|
||||
|
||||
private:
|
||||
static const instr_t kBreakpointInstr =
|
||||
(AL << 28 | 7 << 25 | 1 << 24 | break_point);
|
||||
((AL << 28) | (7 << 25) | (1 << 24) | break_point);
|
||||
static const instr_t kNopInstr =
|
||||
((AL << 28) | (13 << 21));
|
||||
|
||||
Simulator* sim_;
|
||||
|
||||
@ -311,6 +313,14 @@ void Debugger::Debug() {
|
||||
PrintF("Z flag: %d; ", sim_->z_flag_);
|
||||
PrintF("C flag: %d; ", sim_->c_flag_);
|
||||
PrintF("V flag: %d\n", sim_->v_flag_);
|
||||
} else if (strcmp(cmd, "unstop") == 0) {
|
||||
intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
|
||||
Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
|
||||
if (stop_instr->ConditionField() == special_condition) {
|
||||
stop_instr->SetInstructionBits(kNopInstr);
|
||||
} else {
|
||||
PrintF("Not at debugger stop.");
|
||||
}
|
||||
} else {
|
||||
PrintF("Unknown command: %s\n", cmd);
|
||||
}
|
||||
|
@ -237,7 +237,6 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
JSFunction* function,
|
||||
CheckType check) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0: number of arguments
|
||||
// -- r1: receiver
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
@ -322,17 +321,20 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Number of arguments for this function.
|
||||
const int argc = arguments().immediate();
|
||||
|
||||
// Get the function and setup the context.
|
||||
__ mov(r3, Operand(Handle<JSFunction>(function)));
|
||||
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
|
||||
|
||||
// Patch the function on the stack; 1 ~ receiver.
|
||||
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ str(r3, MemOperand(ip, 1 * kPointerSize));
|
||||
__ str(r3, MemOperand(sp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Jump to the cached code (tail call).
|
||||
Handle<Code> code(function->code());
|
||||
__ Jump(code, code_target);
|
||||
ParameterCount expected(function->shared()->formal_parameter_count());
|
||||
__ InvokeCode(code, expected, arguments(), code_target, JUMP_FUNCTION);
|
||||
|
||||
// Handle call cache miss.
|
||||
__ bind(&miss);
|
||||
|
@ -36,7 +36,9 @@
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
|
||||
int32_t NextPowerOf2(uint32_t x) {
|
||||
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
|
||||
// figure 3-3, page 48, where the function is called clp2.
|
||||
uint32_t RoundUpToPowerOf2(uint32_t x) {
|
||||
x = x - 1;
|
||||
x = x | (x >> 1);
|
||||
x = x | (x >> 2);
|
||||
|
25
src/utils.h
25
src/utils.h
@ -40,21 +40,19 @@ static inline bool IsPowerOf2(T x) {
|
||||
}
|
||||
|
||||
|
||||
// Returns smallest power of 2 greater or equal to x (from Hacker's Delight).
|
||||
int32_t NextPowerOf2(uint32_t x);
|
||||
|
||||
|
||||
// The C++ standard leaves the semantics of '>>'
|
||||
// undefined for negative signed operands. Most
|
||||
// implementations do the right thing, though.
|
||||
// The C++ standard leaves the semantics of '>>' undefined for
|
||||
// negative signed operands. Most implementations do the right thing,
|
||||
// though.
|
||||
static inline int ArithmeticShiftRight(int x, int s) {
|
||||
return x >> s;
|
||||
}
|
||||
|
||||
|
||||
// Compute the 0-relative offset of some absolute value x of type T.
|
||||
// This allows conversion of Addresses and integral types into 0-relative
|
||||
// int offsets.
|
||||
// This allows conversion of Addresses and integral types into
|
||||
// 0-relative int offsets.
|
||||
template <typename T>
|
||||
static inline int OffsetFrom(T x) {
|
||||
return x - static_cast<T>(0);
|
||||
@ -62,8 +60,8 @@ static inline int OffsetFrom(T x) {
|
||||
|
||||
|
||||
// Compute the absolute value of type T for some 0-relative offset x.
|
||||
// This allows conversion of 0-relative int offsets into Addresses
|
||||
// and integral types.
|
||||
// This allows conversion of 0-relative int offsets into Addresses and
|
||||
// integral types.
|
||||
template <typename T>
|
||||
static inline T AddressFrom(int x) {
|
||||
return static_cast<T>(0) + x;
|
||||
@ -85,6 +83,11 @@ static inline T RoundUp(T x, int m) {
|
||||
}
|
||||
|
||||
|
||||
// Returns the smallest power of two which is >= x. If you pass in a
|
||||
// number that is already a power of two, it is returned as is.
|
||||
uint32_t RoundUpToPowerOf2(uint32_t x);
|
||||
|
||||
|
||||
template <typename T>
|
||||
static inline bool IsAligned(T value, T alignment) {
|
||||
ASSERT(IsPowerOf2(alignment));
|
||||
@ -114,8 +117,8 @@ static T Min(T a, T b) {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// BitField is a help template for encoding and decode bitfield with unsigned
|
||||
// content.
|
||||
// BitField is a help template for encoding and decode bitfield with
|
||||
// unsigned content.
|
||||
template<class T, int shift, int size>
|
||||
class BitField {
|
||||
public:
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
|
||||
// ECMA-262 - 15.1.1.2.
|
||||
%AddProperty(global, "Infinity", %NumberPositiveInfinity(1), DONT_ENUM | DONT_DELETE);
|
||||
%AddProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
|
||||
|
||||
|
||||
// ECMA-262 - 15.1.1.3.
|
||||
@ -50,7 +50,8 @@
|
||||
|
||||
// ECMA 262 - 15.1.4
|
||||
function $isNaN(number) {
|
||||
return %NumberIsNaN(ToNumber(number));
|
||||
var n = ToNumber(number);
|
||||
return NUMBER_IS_NAN(n);
|
||||
};
|
||||
%AddProperty(global, "isNaN", $isNaN, DONT_ENUM);
|
||||
|
||||
@ -265,10 +266,10 @@ $Object.prototype.constructor = $Object;
|
||||
%AddProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
||||
// ECMA-262 section 15.7.3.4.
|
||||
%AddProperty($Number, "NEGATIVE_INFINITY", %NumberNegativeInfinity(1), DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
%AddProperty($Number, "NEGATIVE_INFINITY", -1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
||||
// ECMA-262 section 15.7.3.5.
|
||||
%AddProperty($Number, "POSITIVE_INFINITY", %NumberPositiveInfinity(1), DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
%AddProperty($Number, "POSITIVE_INFINITY", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
||||
// ECMA-262 section 15.7.4.2.
|
||||
%AddProperty($Number.prototype, "toString", function(radix) {
|
||||
|
Loading…
Reference in New Issue
Block a user