Version 3.19.2
Fill in one-word-fillers for the unused property fields (Chromium issue 240056).
Removed use_system_v8 logic from the mainline gyp file (Chromium issue 226860).
Skip CPU profiler samples where top function's stack frame is not set up properly (issue 2628).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14720 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 6503691..dcaf5a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-05-17: Version 3.19.2
+
+ Fill in one-word-fillers for the unused property fields
+ (Chromium issue 240056).
+
+ Removed use_system_v8 logic from the mainline gyp file
+ (Chromium issue 226860).
+
+ Skip CPU profiler samples where top function's stack frame is not
+ set up properly (issue 2628).
+
+ Performance and stability improvements on all platforms.
+
+
2013-05-14: Version 3.19.1
Fixed missing hole check for loads from Smi arrays when all uses are
diff --git a/build/common.gypi b/build/common.gypi
index 0b1f397..2e3c785 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -29,7 +29,6 @@
{
'variables': {
- 'use_system_v8%': 0,
'msvs_use_common_release': 0,
'gcc_version%': 'unknown',
'CXX%': '${CXX:-$(which g++)}', # Used to assemble a shell command.
diff --git a/include/v8.h b/include/v8.h
index 0cb9df7..96a1d8b 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -3841,25 +3841,29 @@
// CODE_ADD_LINE_POS_INFO and CODE_END_LINE_INFO_RECORDING events.
void* user_data;
+ struct name_t {
+ // Name of the object associated with the code, note that the string is not
+ // zero-terminated.
+ const char* str;
+ // Number of chars in str.
+ size_t len;
+ };
+
+ struct line_info_t {
+ // PC offset
+ size_t offset;
+ // Code postion
+ size_t pos;
+ // The position type.
+ PositionType position_type;
+ };
+
union {
// Only valid for CODE_ADDED.
- struct {
- // Name of the object associated with the code, note that the string is
- // not zero-terminated.
- const char* str;
- // Number of chars in str.
- size_t len;
- } name;
+ struct name_t name;
// Only valid for CODE_ADD_LINE_POS_INFO
- struct {
- // PC offset
- size_t offset;
- // Code postion
- size_t pos;
- // The position type.
- PositionType position_type;
- } line_info;
+ struct line_info_t line_info;
// New location of instructions. Only valid for CODE_MOVED.
void* new_code_start;
@@ -5049,7 +5053,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 118;
+ static const int kEmptyStringRootIndex = 127;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
diff --git a/src/api.cc b/src/api.cc
index 8a6eaf4..f0505cd 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -5953,10 +5953,6 @@
isolate->factory()->NewExternalArray(
static_cast<int>(length), array_type,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
- i::Handle<i::Map> map =
- isolate->factory()->GetElementsTransitionMap(
- obj, elements_kind);
- obj->set_map(*map);
obj->set_elements(*elements);
return obj;
}
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 86da76a..3521589 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -307,8 +307,8 @@
// The optimized code map must never be empty, so check the first elements.
Label install_optimized;
// Speculatively move code object into r4.
- __ ldr(r4, FieldMemOperand(r1, FixedArray::kHeaderSize + kPointerSize));
- __ ldr(r5, FieldMemOperand(r1, FixedArray::kHeaderSize));
+ __ ldr(r4, FieldMemOperand(r1, SharedFunctionInfo::kFirstCodeSlot));
+ __ ldr(r5, FieldMemOperand(r1, SharedFunctionInfo::kFirstContextSlot));
__ cmp(r2, r5);
__ b(eq, &install_optimized);
@@ -317,11 +317,9 @@
__ ldr(r4, FieldMemOperand(r1, FixedArray::kLengthOffset));
__ bind(&loop);
// Do not double check first entry.
-
- __ cmp(r4, Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
+ __ cmp(r4, Operand(Smi::FromInt(SharedFunctionInfo::kSecondEntryIndex)));
__ b(eq, &install_unoptimized);
- __ sub(r4, r4, Operand(
- Smi::FromInt(SharedFunctionInfo::kEntryLength))); // Skip an entry.
+ __ sub(r4, r4, Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
__ add(r5, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(r5, r5, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r5, MemOperand(r5));
@@ -2162,8 +2160,12 @@
GenerateTypeTransition(masm);
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2188,7 +2190,8 @@
__ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &call_runtime);
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
+ StringAddStub string_add_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_stub);
@@ -2459,8 +2462,12 @@
}
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2507,8 +2514,12 @@
GenerateTypeTransition(masm);
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2531,8 +2542,12 @@
}
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2548,7 +2563,8 @@
__ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &left_not_string);
- StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
+ StringAddStub string_add_left_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_left_stub);
@@ -2558,7 +2574,8 @@
__ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
__ b(ge, &call_runtime);
- StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
+ StringAddStub string_add_right_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_right_stub);
@@ -4771,6 +4788,7 @@
__ bind(&megamorphic);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+ __ jmp(&done);
// An uninitialized cache is patched with the function or sentinel to
// indicate the ElementsKind if function is the Array constructor.
@@ -5822,7 +5840,7 @@
__ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
// Make sure that both arguments are strings if not known in advance.
- if (flags_ == NO_STRING_ADD_FLAGS) {
+ if ((flags_ & NO_STRING_ADD_FLAGS) != 0) {
__ JumpIfEitherSmi(r0, r1, &call_runtime);
// Load instance types.
__ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
@@ -6114,15 +6132,49 @@
// Just jump to runtime to add the two strings.
__ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ CallRuntime(Runtime::kStringAdd, 2);
+ }
+ __ Ret();
+ } else {
+ __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ }
if (call_builtin.is_linked()) {
__ bind(&call_builtin);
- __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(builtin_id, CALL_FUNCTION);
+ }
+ __ Ret();
+ } else {
+ __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ }
}
}
+void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+ __ push(r0);
+ __ push(r1);
+}
+
+
+void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
+ __ pop(r1);
+ __ pop(r0);
+}
+
+
void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
int stack_offset,
Register arg,
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 0b1a8b8..863848c 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -211,11 +211,13 @@
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
- NO_STRING_ADD_FLAGS = 0,
+ NO_STRING_ADD_FLAGS = 1 << 0,
// Omit left string check in stub (left is definitely a string).
- NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
+ NO_STRING_CHECK_LEFT_IN_STUB = 1 << 1,
// Omit right string check in stub (right is definitely a string).
- NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
+ NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 2,
+ // Stub needs a frame before calling the runtime
+ ERECT_FRAME = 1 << 3,
// Omit both string checks in stub.
NO_STRING_CHECK_IN_STUB =
NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
@@ -241,6 +243,9 @@
Register scratch4,
Label* slow);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateRegisterArgsPop(MacroAssembler* masm);
+
const StringAddFlags flags_;
};
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 5a0a04f..d973889 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -276,7 +276,7 @@
if (FLAG_trace_osr) {
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => node=%u, frame=%d->%d]\n",
ast_id,
input_frame_size,
@@ -370,194 +370,12 @@
PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
ok ? "finished" : "aborted",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
}
}
-// This code is very similar to ia32 code, but relies on register names (fp, sp)
-// and how the frame is laid out.
-void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
- int frame_index) {
- // Read the ast node id, function, and frame height for this output frame.
- BailoutId node_id = BailoutId(iterator->Next());
- JSFunction* function;
- if (frame_index != 0) {
- function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- } else {
- int closure_id = iterator->Next();
- USE(closure_id);
- ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
- function = function_;
- }
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating ");
- function->PrintName();
- PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
- }
-
- // The 'fixed' part of the frame consists of the incoming parameters and
- // the part described by JavaScriptFrameConstants.
- unsigned fixed_frame_size = ComputeFixedSize(function);
- unsigned input_frame_size = input_->GetFrameSize();
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
-
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
- ASSERT(frame_index >= 0 && frame_index < output_count_);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address for the bottommost output frame can be computed from
- // the input frame pointer and the output frame's height. For all
- // subsequent output frames, it can be computed from the previous one's
- // top address and the current frame's size.
- uint32_t top_address;
- if (is_bottommost) {
- // 2 = context and function in the frame.
- top_address =
- input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = function->shared()->formal_parameter_count() + 1;
- unsigned output_offset = output_frame_size;
- unsigned input_offset = input_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- input_offset -= (parameter_count * kPointerSize);
-
- // There are no translation commands for the caller's pc and fp, the
- // context, and the function. Synthesize their values and set them up
- // explicitly.
- //
- // The caller's pc for the bottommost output frame is the same as in the
- // input frame. For all subsequent output frames, it can be read from the
- // previous one. This frame's pc can be computed from the non-optimized
- // function code and AST id of the bailout.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- intptr_t value;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetPc();
- }
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The caller's frame pointer for the bottommost output frame is the same
- // as in the input frame. For all subsequent output frames, it can be
- // read from the previous one. Also compute and set this frame's frame
- // pointer.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetFp();
- }
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value);
- output_frame->SetFp(fp_value);
- if (is_topmost) {
- output_frame->SetRegister(fp.code(), fp_value);
- }
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // For the bottommost output frame the context can be gotten from the input
- // frame. For all subsequent output frames it can be gotten from the function
- // so long as we don't inline functions that need local contexts.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = reinterpret_cast<intptr_t>(function->context());
- }
- output_frame->SetFrameSlot(output_offset, value);
- output_frame->SetContext(value);
- if (is_topmost) output_frame->SetRegister(cp.code(), value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The function was mentioned explicitly in the BEGIN_FRAME.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(function);
- // The function for the bottommost output frame should also agree with the
- // input frame.
- ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Translate the rest of the frame.
- for (unsigned i = 0; i < height; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- ASSERT(0 == output_offset);
-
- // Compute this frame's PC, state, and continuation.
- Code* non_optimized_code = function->shared()->code();
- FixedArray* raw_data = non_optimized_code->deoptimization_data();
- DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
- Address start = non_optimized_code->instruction_start();
- unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
- unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
- uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
- output_frame->SetPc(pc_value);
- if (is_topmost) {
- output_frame->SetRegister(pc.code(), pc_value);
- }
-
- FullCodeGenerator::State state =
- FullCodeGenerator::StateField::decode(pc_and_state);
- output_frame->SetState(Smi::FromInt(state));
-
-
- // Set the continuation for the topmost frame.
- if (is_topmost && bailout_type_ != DEBUGGER) {
- Builtins* builtins = isolate_->builtins();
- Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
- if (bailout_type_ == LAZY) {
- continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
- } else if (bailout_type_ == SOFT) {
- continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
- } else {
- ASSERT(bailout_type_ == EAGER);
- }
- output_frame->SetContinuation(
- reinterpret_cast<uint32_t>(continuation->entry()));
- }
-}
-
-
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
@@ -601,6 +419,12 @@
}
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+ // There is no dynamic alignment padding on ARM in the input frame.
+ return false;
+}
+
+
#define __ masm()->
// This code tries to be close to ia32 code so that any changes can be
diff --git a/src/arm/frames-arm.cc b/src/arm/frames-arm.cc
index 5cbe77a..f5a7dbd 100644
--- a/src/arm/frames-arm.cc
+++ b/src/arm/frames-arm.cc
@@ -45,6 +45,10 @@
}
+Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
+Register JavaScriptFrame::context_register() { return cp; }
+
+
Register StubFailureTrampolineFrame::fp_register() { return v8::internal::fp; }
Register StubFailureTrampolineFrame::context_register() { return cp; }
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 0bc1f48..5b6ce4c 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -175,6 +175,7 @@
// Adjust FP to point to saved FP.
__ add(fp, sp, Operand(2 * kPointerSize));
}
+ info->AddNoFrameRange(0, masm_->pc_offset());
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
@@ -438,9 +439,11 @@
PredictableCodeSizeScope predictable(masm_, -1);
__ RecordJSReturn();
masm_->mov(sp, fp);
+ int no_frame_start = masm_->pc_offset();
masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
masm_->add(sp, sp, Operand(sp_delta));
masm_->Jump(lr);
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
}
#ifdef DEBUG
@@ -1961,8 +1964,102 @@
break;
}
- case Yield::DELEGATING:
- UNIMPLEMENTED();
+ case Yield::DELEGATING: {
+ VisitForStackValue(expr->generator_object());
+
+ // Initial stack layout is as follows:
+ // [sp + 1 * kPointerSize] iter
+ // [sp + 0 * kPointerSize] g
+
+ Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+ // Initial send value is undefined.
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
+ __ b(&l_send);
+
+ // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
+ __ bind(&l_catch);
+ handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+ __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
+ __ push(r3); // iter
+ __ push(r0); // exception
+ __ mov(r0, r3); // iter
+ __ push(r0); // push LoadIC state
+ __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw"
+ Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(throw_ic); // iter.throw in r0
+ __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+ __ jmp(&l_call);
+
+ // try { received = yield result.value }
+ __ bind(&l_try);
+ __ pop(r0); // result.value
+ __ PushTryHandler(StackHandler::CATCH, expr->index());
+ const int handler_size = StackHandlerConstants::kSize;
+ __ push(r0); // result.value
+ __ ldr(r3, MemOperand(sp, (0 + 1) * kPointerSize + handler_size)); // g
+ __ push(r3); // g
+ __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+ __ ldr(context_register(),
+ MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &l_resume);
+ EmitReturnIteratorResult(false);
+ __ bind(&l_resume); // received in r0
+ __ PopTryHandler();
+
+ // receiver = iter; f = iter.send; arg = received;
+ __ bind(&l_send);
+ __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
+ __ push(r3); // iter
+ __ push(r0); // received
+ __ mov(r0, r3); // iter
+ __ push(r0); // push LoadIC state
+ __ LoadRoot(r2, Heap::ksend_stringRootIndex); // "send"
+ Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(send_ic); // iter.send in r0
+ __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+
+ // result = f.call(receiver, arg);
+ __ bind(&l_call);
+ Label l_call_runtime;
+ __ JumpIfSmi(r0, &l_call_runtime);
+ __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
+ __ b(ne, &l_call_runtime);
+ __ mov(r1, r0);
+ ParameterCount count(1);
+ __ InvokeFunction(r1, count, CALL_FUNCTION,
+ NullCallWrapper(), CALL_AS_METHOD);
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ jmp(&l_loop);
+ __ bind(&l_call_runtime);
+ __ push(r0);
+ __ CallRuntime(Runtime::kCall, 3);
+
+ // val = result.value; if (!result.done) goto l_try;
+ __ bind(&l_loop);
+ // result.value
+ __ push(r0); // save result
+ __ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value"
+ Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(value_ic); // result.value in r0
+ __ pop(r1); // result
+ __ push(r0); // result.value
+ __ mov(r0, r1); // result
+ __ push(r0); // push LoadIC state
+ __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done"
+ Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(done_ic); // result.done in r0
+ __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+ ToBooleanStub stub(r0);
+ __ CallStub(&stub);
+ __ cmp(r0, Operand(0));
+ __ b(eq, &l_try);
+
+ // result.value
+ __ pop(r0); // result.value
+ context()->DropAndPlug(2, r0); // drop iter and g
+ break;
+ }
}
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 08a940d..e1bb69e 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -217,15 +217,6 @@
}
-void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if ");
- value()->PrintTo(stream);
- stream->Add(kind() == kStrictEquality ? " === " : " == ");
- stream->Add(nil() == kNullValue ? "null" : "undefined");
- stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
value()->PrintTo(stream);
@@ -989,6 +980,10 @@
}
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+ return new(zone()) LDebugBreak();
+}
+
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ASSERT(instr->value()->representation().IsTagged());
@@ -1719,12 +1714,6 @@
}
-LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()));
-}
-
-
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
@@ -1837,7 +1826,7 @@
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegister(instr->index());
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseTempRegister(instr->value());
LSeqStringSetChar* result =
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
return DefineAsRegister(result);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 407e667..9bcd44a 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -89,6 +89,7 @@
V(ConstantI) \
V(ConstantT) \
V(Context) \
+ V(DebugBreak) \
V(DeclareGlobals) \
V(DeleteProperty) \
V(Deoptimize) \
@@ -113,7 +114,6 @@
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
- V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
@@ -696,6 +696,12 @@
};
+class LDebugBreak: public LTemplateInstruction<0, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
@@ -885,24 +891,6 @@
};
-class LIsNilAndBranch: public LControlInstruction<1, 0> {
- public:
- explicit LIsNilAndBranch(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
-
- EqualityKind kind() const { return hydrogen()->kind(); }
- NilValue nil() const { return hydrogen()->nil(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsObjectAndBranch: public LControlInstruction<1, 1> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 4f5ab57..96adb2f 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2198,6 +2198,11 @@
}
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
+ __ stop("LBreak");
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2419,48 +2424,6 @@
}
-void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
- Register scratch = scratch0();
- Register reg = ToRegister(instr->value());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- // If the expression is known to be untagged or a smi, then it's definitely
- // not null, and it can't be a an undetectable object.
- if (instr->hydrogen()->representation().IsSpecialization() ||
- instr->hydrogen()->type().IsSmi()) {
- EmitGoto(false_block);
- return;
- }
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- Heap::RootListIndex nil_value = instr->nil() == kNullValue ?
- Heap::kNullValueRootIndex :
- Heap::kUndefinedValueRootIndex;
- __ LoadRoot(ip, nil_value);
- __ cmp(reg, ip);
- if (instr->kind() == kStrictEquality) {
- EmitBranch(true_block, false_block, eq);
- } else {
- Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ?
- Heap::kUndefinedValueRootIndex :
- Heap::kNullValueRootIndex;
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ b(eq, true_label);
- __ LoadRoot(ip, other_nil_value);
- __ cmp(reg, ip);
- __ b(eq, true_label);
- __ JumpIfSmi(reg, false_label);
- // Check for undetectable objects by looking in the bit field in
- // the map. The object has already been smi checked.
- __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
- __ tst(scratch, Operand(1 << Map::kIsUndetectable));
- EmitBranch(true_block, false_block, ne);
- }
-}
-
-
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Label* is_not_object,
@@ -2940,9 +2903,11 @@
count++;
}
}
+ int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
+ no_frame_start = masm_->pc_offset();
}
if (instr->has_constant_parameter_count()) {
int parameter_count = ToInteger32(instr->constant_parameter_count());
@@ -2958,6 +2923,10 @@
}
__ Jump(lr);
+
+ if (no_frame_start != -1) {
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+ }
}
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index af65bc7..e91f079 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -412,7 +412,7 @@
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
int value = *cur;
Heap* current_heap = v8::internal::Isolate::Current()->heap();
- if (current_heap->Contains(obj) || ((value & 1) == 0)) {
+ if (((value & 1) == 0) || current_heap->Contains(obj)) {
PrintF(" (");
if ((value & 1) == 0) {
PrintF("smi %d", value / 2);
diff --git a/src/array.js b/src/array.js
index 54f0b48..599fd5c 100644
--- a/src/array.js
+++ b/src/array.js
@@ -416,6 +416,26 @@
}
+function ObservedArrayPush() {
+ var n = TO_UINT32(this.length);
+ var m = %_ArgumentsLength();
+
+ EnqueueSpliceRecord(this, n, [], 0, m);
+
+ try {
+ BeginPerformSplice(this);
+
+ for (var i = 0; i < m; i++) {
+ this[i+n] = %_Arguments(i);
+ }
+ this.length = n + m;
+ } finally {
+ EndPerformSplice(this);
+ }
+
+ return this.length;
+}
+
// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
@@ -424,6 +444,9 @@
["Array.prototype.push"]);
}
+ if (%IsObserved(this))
+ return ObservedArrayPush.apply(this, arguments);
+
var n = TO_UINT32(this.length);
var m = %_ArgumentsLength();
for (var i = 0; i < m; i++) {
diff --git a/src/ast.h b/src/ast.h
index 9ffb00d..d697da7 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -286,6 +286,7 @@
}
void Add(Handle<Map> handle, Zone* zone) {
+ ASSERT(!handle->is_deprecated());
list_.Add(handle.location(), zone);
}
@@ -1992,6 +1993,18 @@
Kind yield_kind() const { return yield_kind_; }
virtual int position() const { return pos_; }
+ // Delegating yield surrounds the "yield" in a "try/catch". This index
+ // locates the catch handler in the handler table, and is equivalent to
+ // TryCatchStatement::index().
+ int index() const {
+ ASSERT(yield_kind() == DELEGATING);
+ return index_;
+ }
+ void set_index(int index) {
+ ASSERT(yield_kind() == DELEGATING);
+ index_ = index;
+ }
+
protected:
Yield(Isolate* isolate,
Expression* generator_object,
@@ -2002,12 +2015,14 @@
generator_object_(generator_object),
expression_(expression),
yield_kind_(yield_kind),
+ index_(-1),
pos_(pos) { }
private:
Expression* generator_object_;
Expression* expression_;
Kind yield_kind_;
+ int index_;
int pos_;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index beb3cb5..85812ca 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -201,7 +201,8 @@
ElementsKind elements_kind);
bool InstallNatives();
- Handle<JSFunction> InstallTypedArray(const char* name);
+ Handle<JSFunction> InstallTypedArray(const char* name,
+ ElementsKind elementsKind);
bool InstallExperimentalNatives();
void InstallBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
@@ -349,7 +350,8 @@
int instance_size,
Handle<JSObject> prototype,
Builtins::Name call,
- bool is_ecma_native) {
+ bool install_initial_map,
+ bool set_instance_class_name) {
Isolate* isolate = target->GetIsolate();
Factory* factory = isolate->factory();
Handle<String> internalized_name = factory->InternalizeUtf8String(name);
@@ -361,7 +363,7 @@
instance_size,
prototype,
call_code,
- is_ecma_native);
+ install_initial_map);
PropertyAttributes attributes;
if (target->IsJSBuiltinsObject()) {
attributes =
@@ -372,7 +374,7 @@
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
target, internalized_name, function, attributes));
- if (is_ecma_native) {
+ if (set_instance_class_name) {
function->shared()->set_instance_class_name(*internalized_name);
}
function->shared()->set_native(true);
@@ -843,13 +845,13 @@
// Install global Function object
InstallFunction(global, "Function", JS_FUNCTION_TYPE, JSFunction::kSize,
- empty_function, Builtins::kIllegal, true); // ECMA native.
+ empty_function, Builtins::kIllegal, true, true);
{ // --- A r r a y ---
Handle<JSFunction> array_function =
InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
isolate->initial_object_prototype(),
- Builtins::kArrayCode, true);
+ Builtins::kArrayCode, true, true);
array_function->shared()->DontAdaptArguments();
// This seems a bit hackish, but we need to make sure Array.length
@@ -893,7 +895,7 @@
Handle<JSFunction> number_fun =
InstallFunction(global, "Number", JS_VALUE_TYPE, JSValue::kSize,
isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_number_function(*number_fun);
}
@@ -901,7 +903,7 @@
Handle<JSFunction> boolean_fun =
InstallFunction(global, "Boolean", JS_VALUE_TYPE, JSValue::kSize,
isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_boolean_function(*boolean_fun);
}
@@ -909,7 +911,7 @@
Handle<JSFunction> string_fun =
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
string_fun->shared()->set_construct_stub(
isolate->builtins()->builtin(Builtins::kStringConstructCode));
native_context()->set_string_function(*string_fun);
@@ -937,7 +939,7 @@
Handle<JSFunction> date_fun =
InstallFunction(global, "Date", JS_DATE_TYPE, JSDate::kSize,
isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_date_function(*date_fun);
}
@@ -948,7 +950,7 @@
Handle<JSFunction> regexp_fun =
InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
isolate->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_regexp_function(*regexp_fun);
ASSERT(regexp_fun->has_initial_map());
@@ -1263,11 +1265,18 @@
}
-Handle<JSFunction> Genesis::InstallTypedArray(const char* name) {
+Handle<JSFunction> Genesis::InstallTypedArray(
+ const char* name, ElementsKind elementsKind) {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
- return InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
+ Handle<JSFunction> result = InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
JSTypedArray::kSize, isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, false, true);
+
+ Handle<Map> initial_map = isolate()->factory()->NewMap(
+ JS_TYPED_ARRAY_TYPE, JSTypedArray::kSize, elementsKind);
+ result->set_initial_map(*initial_map);
+ initial_map->set_constructor(*result);
+ return result;
}
@@ -1282,7 +1291,7 @@
Handle<JSFunction> symbol_fun =
InstallFunction(global, "Symbol", JS_VALUE_TYPE, JSValue::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_symbol_function(*symbol_fun);
}
@@ -1290,17 +1299,17 @@
{ // -- S e t
InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
}
{ // -- M a p
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
}
{ // -- W e a k M a p
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
}
}
@@ -1310,29 +1319,38 @@
InstallFunction(global, "ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
JSArrayBuffer::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Builtins::kIllegal, true, true);
native_context()->set_array_buffer_fun(*array_buffer_fun);
}
if (FLAG_harmony_typed_arrays) {
// -- T y p e d A r r a y s
- Handle<JSFunction> int8_fun = InstallTypedArray("Int8Array");
+ Handle<JSFunction> int8_fun = InstallTypedArray("Int8Array",
+ EXTERNAL_BYTE_ELEMENTS);
native_context()->set_int8_array_fun(*int8_fun);
- Handle<JSFunction> uint8_fun = InstallTypedArray("Uint8Array");
+ Handle<JSFunction> uint8_fun = InstallTypedArray("Uint8Array",
+ EXTERNAL_UNSIGNED_BYTE_ELEMENTS);
native_context()->set_uint8_array_fun(*uint8_fun);
- Handle<JSFunction> int16_fun = InstallTypedArray("Int16Array");
+ Handle<JSFunction> int16_fun = InstallTypedArray("Int16Array",
+ EXTERNAL_SHORT_ELEMENTS);
native_context()->set_int16_array_fun(*int16_fun);
- Handle<JSFunction> uint16_fun = InstallTypedArray("Uint16Array");
+ Handle<JSFunction> uint16_fun = InstallTypedArray("Uint16Array",
+ EXTERNAL_UNSIGNED_SHORT_ELEMENTS);
native_context()->set_uint16_array_fun(*uint16_fun);
- Handle<JSFunction> int32_fun = InstallTypedArray("Int32Array");
+ Handle<JSFunction> int32_fun = InstallTypedArray("Int32Array",
+ EXTERNAL_INT_ELEMENTS);
native_context()->set_int32_array_fun(*int32_fun);
- Handle<JSFunction> uint32_fun = InstallTypedArray("Uint32Array");
+ Handle<JSFunction> uint32_fun = InstallTypedArray("Uint32Array",
+ EXTERNAL_UNSIGNED_INT_ELEMENTS);
native_context()->set_uint32_array_fun(*uint32_fun);
- Handle<JSFunction> float_fun = InstallTypedArray("Float32Array");
+ Handle<JSFunction> float_fun = InstallTypedArray("Float32Array",
+ EXTERNAL_FLOAT_ELEMENTS);
native_context()->set_float_array_fun(*float_fun);
- Handle<JSFunction> double_fun = InstallTypedArray("Float64Array");
+ Handle<JSFunction> double_fun = InstallTypedArray("Float64Array",
+ EXTERNAL_DOUBLE_ELEMENTS);
native_context()->set_double_array_fun(*double_fun);
- Handle<JSFunction> uint8c_fun = InstallTypedArray("Uint8ClampedArray");
+ Handle<JSFunction> uint8c_fun = InstallTypedArray("Uint8ClampedArray",
+ EXTERNAL_PIXEL_ELEMENTS);
native_context()->set_uint8c_array_fun(*uint8c_fun);
}
@@ -1345,11 +1363,11 @@
InstallFunction(builtins, "GeneratorFunctionPrototype",
JS_FUNCTION_TYPE, JSFunction::kHeaderSize,
generator_object_prototype, Builtins::kIllegal,
- false);
+ false, false);
InstallFunction(builtins, "GeneratorFunction",
JS_FUNCTION_TYPE, JSFunction::kSize,
generator_function_prototype, Builtins::kIllegal,
- false);
+ false, false);
// Create maps for generator functions and their prototypes. Store those
// maps in the native context.
@@ -1577,7 +1595,7 @@
JSArray::kSize,
isolate()->initial_object_prototype(),
Builtins::kInternalArrayCode,
- true);
+ true, true);
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
SetPrototype(array_function, prototype);
@@ -1677,7 +1695,7 @@
Handle<JSFunction> script_fun =
InstallFunction(builtins, "Script", JS_VALUE_TYPE, JSValue::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, false);
+ Builtins::kIllegal, false, false);
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
SetPrototype(script_fun, prototype);
@@ -1833,7 +1851,7 @@
InstallFunction(builtins, "OpaqueReference", JS_VALUE_TYPE,
JSValue::kSize,
isolate()->initial_object_prototype(),
- Builtins::kIllegal, false);
+ Builtins::kIllegal, false, false);
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
SetPrototype(opaque_reference_fun, prototype);
@@ -1897,12 +1915,12 @@
InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Handle<JSObject>::null(),
Builtins::kFunctionCall,
- false);
+ false, false);
Handle<JSFunction> apply =
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Handle<JSObject>::null(),
Builtins::kFunctionApply,
- false);
+ false, false);
// Make sure that Function.prototype.call appears to be compiled.
// The code will never be called, but inline caching for call will
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index aa2c821..312febc 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -232,37 +232,37 @@
void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
switch (op_) {
case Token::ADD:
- __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::ADD, CALL_FUNCTION);
break;
case Token::SUB:
- __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::SUB, CALL_FUNCTION);
break;
case Token::MUL:
- __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::MUL, CALL_FUNCTION);
break;
case Token::DIV:
- __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::DIV, CALL_FUNCTION);
break;
case Token::MOD:
- __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::MOD, CALL_FUNCTION);
break;
case Token::BIT_OR:
- __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::BIT_OR, CALL_FUNCTION);
break;
case Token::BIT_AND:
- __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::BIT_AND, CALL_FUNCTION);
break;
case Token::BIT_XOR:
- __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::BIT_XOR, CALL_FUNCTION);
break;
case Token::SAR:
- __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::SAR, CALL_FUNCTION);
break;
case Token::SHR:
- __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::SHR, CALL_FUNCTION);
break;
case Token::SHL:
- __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
+ __ InvokeBuiltin(Builtins::SHL, CALL_FUNCTION);
break;
default:
UNREACHABLE();
@@ -408,41 +408,50 @@
}
-CompareNilICStub::Types CompareNilICStub::GetPatchedICFlags(
- Code::ExtraICState extra_ic_state,
- Handle<Object> object,
- bool* already_monomorphic) {
- Types types = TypesField::decode(extra_ic_state);
- NilValue nil = NilValueField::decode(extra_ic_state);
- EqualityKind kind = EqualityKindField::decode(extra_ic_state);
- ASSERT(types != CompareNilICStub::kFullCompare);
- *already_monomorphic =
- (types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0;
- if (kind == kStrictEquality) {
- if (nil == kNullValue) {
- return CompareNilICStub::kCompareAgainstNull;
- } else {
- return CompareNilICStub::kCompareAgainstUndefined;
- }
+void CompareNilICStub::Record(Handle<Object> object) {
+ ASSERT(types_ != Types::FullCompare());
+ if (equality_kind_ == kStrictEquality) {
+ // When testing for strict equality only one value will evaluate to true
+ types_.RemoveAll();
+ types_.Add((nil_value_ == kNullValue) ? NULL_TYPE:
+ UNDEFINED);
} else {
if (object->IsNull()) {
- types = static_cast<CompareNilICStub::Types>(
- types | CompareNilICStub::kCompareAgainstNull);
+ types_.Add(NULL_TYPE);
} else if (object->IsUndefined()) {
- types = static_cast<CompareNilICStub::Types>(
- types | CompareNilICStub::kCompareAgainstUndefined);
+ types_.Add(UNDEFINED);
} else if (object->IsUndetectableObject() ||
object->IsOddball() ||
!object->IsHeapObject()) {
- types = CompareNilICStub::kFullCompare;
- } else if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
- types = CompareNilICStub::kFullCompare;
+ types_ = Types::FullCompare();
+ } else if (IsMonomorphic()) {
+ types_ = Types::FullCompare();
} else {
- types = static_cast<CompareNilICStub::Types>(
- types | CompareNilICStub::kCompareAgainstMonomorphicMap);
+ types_.Add(MONOMORPHIC_MAP);
}
}
- return types;
+}
+
+
+void CompareNilICStub::PrintName(StringStream* stream) {
+ stream->Add("CompareNilICStub_");
+ types_.Print(stream);
+ stream->Add((nil_value_ == kNullValue) ? "(NullValue|":
+ "(UndefinedValue|");
+ stream->Add((equality_kind_ == kStrictEquality) ? "StrictEquality)":
+ "NonStrictEquality)");
+}
+
+
+void CompareNilICStub::Types::Print(StringStream* stream) const {
+ stream->Add("(");
+ SimpleListPrinter printer(stream);
+ if (IsEmpty()) printer.Add("None");
+ if (Contains(UNDEFINED)) printer.Add("Undefined");
+ if (Contains(NULL_TYPE)) printer.Add("Null");
+ if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap");
+ if (Contains(UNDETECTABLE)) printer.Add("Undetectable");
+ stream->Add(")");
}
@@ -552,15 +561,18 @@
void ToBooleanStub::Types::Print(StringStream* stream) const {
- if (IsEmpty()) stream->Add("None");
- if (Contains(UNDEFINED)) stream->Add("Undefined");
- if (Contains(BOOLEAN)) stream->Add("Bool");
- if (Contains(NULL_TYPE)) stream->Add("Null");
- if (Contains(SMI)) stream->Add("Smi");
- if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
- if (Contains(STRING)) stream->Add("String");
- if (Contains(SYMBOL)) stream->Add("Symbol");
- if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
+ stream->Add("(");
+ SimpleListPrinter printer(stream);
+ if (IsEmpty()) printer.Add("None");
+ if (Contains(UNDEFINED)) printer.Add("Undefined");
+ if (Contains(BOOLEAN)) printer.Add("Bool");
+ if (Contains(NULL_TYPE)) printer.Add("Null");
+ if (Contains(SMI)) printer.Add("Smi");
+ if (Contains(SPEC_OBJECT)) printer.Add("SpecObject");
+ if (Contains(STRING)) printer.Add("String");
+ if (Contains(SYMBOL)) printer.Add("Symbol");
+ if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
+ stream->Add(")");
}
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 646aee2..aa6a410 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -1047,27 +1047,70 @@
class CompareNilICStub : public HydrogenCodeStub {
public:
- enum Types {
- kCompareAgainstNull = 1 << 0,
- kCompareAgainstUndefined = 1 << 1,
- kCompareAgainstMonomorphicMap = 1 << 2,
- kCompareAgainstUndetectable = 1 << 3,
- kFullCompare = kCompareAgainstNull | kCompareAgainstUndefined |
- kCompareAgainstUndetectable
+ enum Type {
+ UNDEFINED,
+ NULL_TYPE,
+ MONOMORPHIC_MAP,
+ UNDETECTABLE,
+ NUMBER_OF_TYPES
};
+ class Types : public EnumSet<Type, byte> {
+ public:
+ Types() : EnumSet<Type, byte>(0) { }
+ explicit Types(byte bits) : EnumSet<Type, byte>(bits) { }
+
+ static Types FullCompare() {
+ Types set;
+ set.Add(UNDEFINED);
+ set.Add(NULL_TYPE);
+ set.Add(UNDETECTABLE);
+ return set;
+ }
+
+ void Print(StringStream* stream) const;
+ };
+
+ // At most 6 different types can be distinguished, because the Code object
+ // only has room for a single byte to hold a set and there are two more
+ // boolean flags we need to store. :-P
+ STATIC_ASSERT(NUMBER_OF_TYPES <= 6);
+
CompareNilICStub(EqualityKind kind, NilValue nil, Types types)
- : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), bit_field_(0) {
- bit_field_ = EqualityKindField::encode(kind) |
- NilValueField::encode(nil) |
- TypesField::encode(types);
+ : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), types_(types) {
+ equality_kind_ = kind;
+ nil_value_ = nil;
+ }
+
+ explicit CompareNilICStub(Code::ExtraICState ic_state)
+ : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
+ equality_kind_ = EqualityKindField::decode(ic_state);
+ nil_value_ = NilValueField::decode(ic_state);
+ types_ = Types(ExtractTypesFromExtraICState(ic_state));
+ }
+
+ static Handle<Code> GetUninitialized(Isolate* isolate,
+ EqualityKind kind,
+ NilValue nil) {
+ return CompareNilICStub(kind, nil, CODE_STUB_IS_MISS).GetCode(isolate);
+ }
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ static void InitializeForIsolate(Isolate* isolate) {
+ CompareNilICStub compare_stub(kStrictEquality, kNullValue,
+ CODE_STUB_IS_MISS);
+ compare_stub.InitializeInterfaceDescriptor(
+ isolate,
+ isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC));
}
virtual InlineCacheState GetICState() {
- Types types = GetTypes();
- if (types == kFullCompare) {
+ if (types_ == Types::FullCompare()) {
return MEGAMORPHIC;
- } else if ((types & kCompareAgainstMonomorphicMap) != 0) {
+ } else if (types_.Contains(MONOMORPHIC_MAP)) {
return MONOMORPHIC;
} else {
return PREMONOMORPHIC;
@@ -1078,64 +1121,55 @@
Handle<Code> GenerateCode();
- static Handle<Code> GetUninitialized(Isolate* isolate,
- EqualityKind kind,
- NilValue nil) {
- return CompareNilICStub(kind, nil).GetCode(isolate);
- }
-
- virtual void InitializeInterfaceDescriptor(
- Isolate* isolate,
- CodeStubInterfaceDescriptor* descriptor);
-
- static void InitializeForIsolate(Isolate* isolate) {
- CompareNilICStub compare_stub(kStrictEquality, kNullValue);
- compare_stub.InitializeInterfaceDescriptor(
- isolate,
- isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC));
- }
-
+ // extra ic state = nil_value | equality_kind | type_n-1 | ... | type_0
virtual Code::ExtraICState GetExtraICState() {
- return bit_field_;
+ return NilValueField::encode(nil_value_) |
+ EqualityKindField::encode(equality_kind_) |
+ types_.ToIntegral();
}
-
- EqualityKind GetKind() { return EqualityKindField::decode(bit_field_); }
- NilValue GetNilValue() { return NilValueField::decode(bit_field_); }
- Types GetTypes() { return TypesField::decode(bit_field_); }
-
- static Types TypesFromExtraICState(
+ static byte ExtractTypesFromExtraICState(
Code::ExtraICState state) {
- return TypesField::decode(state);
- }
- static EqualityKind EqualityKindFromExtraICState(
- Code::ExtraICState state) {
- return EqualityKindField::decode(state);
- }
- static NilValue NilValueFromExtraICState(Code::ExtraICState state) {
- return NilValueField::decode(state);
+ return state & ((1<<NUMBER_OF_TYPES)-1);
}
- static Types GetPatchedICFlags(Code::ExtraICState extra_ic_state,
- Handle<Object> object,
- bool* already_monomorphic);
+ void Record(Handle<Object> object);
+
+ bool IsMonomorphic() const { return types_.Contains(MONOMORPHIC_MAP); }
+ EqualityKind GetKind() const { return equality_kind_; }
+ NilValue GetNilValue() const { return nil_value_; }
+ Types GetTypes() const { return types_; }
+ void ClearTypes() { types_.RemoveAll(); }
+ void SetKind(EqualityKind kind) { equality_kind_ = kind; }
+
+ virtual void PrintName(StringStream* stream);
private:
friend class CompareNilIC;
- class EqualityKindField : public BitField<EqualityKind, 0, 1> {};
- class NilValueField : public BitField<NilValue, 1, 1> {};
- class TypesField : public BitField<Types, 3, 4> {};
-
- CompareNilICStub(EqualityKind kind, NilValue nil)
- : HydrogenCodeStub(CODE_STUB_IS_MISS), bit_field_(0) {
- bit_field_ = EqualityKindField::encode(kind) |
- NilValueField::encode(nil);
+ CompareNilICStub(EqualityKind kind, NilValue nil,
+ InitializationState init_state)
+ : HydrogenCodeStub(init_state), types_(0) {
+ equality_kind_ = kind;
+ nil_value_ = nil;
}
- virtual CodeStub::Major MajorKey() { return CompareNilIC; }
- virtual int NotMissMinorKey() { return bit_field_; }
+ CompareNilICStub(Code::ExtraICState ic_state, InitializationState init_state)
+ : HydrogenCodeStub(init_state) {
+ equality_kind_ = EqualityKindField::decode(ic_state);
+ nil_value_ = NilValueField::decode(ic_state);
+ types_ = Types(ExtractTypesFromExtraICState(ic_state));
+ }
- int bit_field_;
+ class EqualityKindField : public BitField<EqualityKind, NUMBER_OF_TYPES, 1> {
+ };
+ class NilValueField : public BitField<NilValue, NUMBER_OF_TYPES+1, 1> {};
+
+ virtual CodeStub::Major MajorKey() { return CompareNilIC; }
+ virtual int NotMissMinorKey() { return GetExtraICState(); }
+
+ EqualityKind equality_kind_;
+ NilValue nil_value_;
+ Types types_;
DISALLOW_COPY_AND_ASSIGN(CompareNilICStub);
};
@@ -1795,26 +1829,17 @@
// only has room for a single byte to hold a set of these types. :-P
STATIC_ASSERT(NUMBER_OF_TYPES <= 8);
- class Types {
+ class Types : public EnumSet<Type, byte> {
public:
Types() {}
- explicit Types(byte bits) : set_(bits) {}
+ explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
- bool IsEmpty() const { return set_.IsEmpty(); }
- bool Contains(Type type) const { return set_.Contains(type); }
- bool ContainsAnyOf(Types types) const {
- return set_.ContainsAnyOf(types.set_);
- }
- void Add(Type type) { set_.Add(type); }
- byte ToByte() const { return set_.ToIntegral(); }
+ byte ToByte() const { return ToIntegral(); }
void Print(StringStream* stream) const;
void TraceTransition(Types to) const;
bool Record(Handle<Object> object);
bool NeedsMap() const;
bool CanBeUndetectable() const;
-
- private:
- EnumSet<Type, byte> set_;
};
static Types no_types() { return Types(); }
@@ -1831,7 +1856,8 @@
private:
Major MajorKey() { return ToBoolean; }
- int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) | types_.ToByte(); }
+ int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) |
+ types_.ToByte(); }
virtual void FinishCode(Handle<Code> code) {
code->set_to_boolean_state(types_.ToByte());
diff --git a/src/compiler.cc b/src/compiler.cc
index 76fb726..5045758 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -103,6 +103,8 @@
code_stub_ = NULL;
prologue_offset_ = kPrologueOffsetNotSet;
opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
+ no_frame_ranges_ = isolate->cpu_profiler()->is_profiling()
+ ? new List<OffsetRange>(2) : NULL;
if (mode == STUB) {
mode_ = STUB;
return;
@@ -121,6 +123,7 @@
CompilationInfo::~CompilationInfo() {
delete deferred_handles_;
+ delete no_frame_ranges_;
}
@@ -568,6 +571,7 @@
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*info->code(),
*result,
+ info,
String::cast(script->name())));
GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
script,
@@ -580,6 +584,7 @@
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*info->code(),
*result,
+ info,
isolate->heap()->empty_string()));
GDBJIT(AddCode(Handle<String>(), script, info->code(), info));
}
@@ -807,6 +812,10 @@
// reset this bit when lazy compiling the code again.
if (shared->optimization_disabled()) code->set_optimizable(false);
+ if (shared->code() == *code) {
+ // Do not send compilation event for the same code twice.
+ return;
+ }
Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
}
@@ -1151,6 +1160,7 @@
CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code,
*shared,
+ info,
String::cast(script->name()),
line_num));
} else {
@@ -1158,6 +1168,7 @@
CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code,
*shared,
+ info,
shared->DebugName()));
}
}
diff --git a/src/compiler.h b/src/compiler.h
index 00074c8..dbb513c 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -47,6 +47,12 @@
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
};
+struct OffsetRange {
+ OffsetRange(int from, int to) : from(from), to(to) {}
+ int from;
+ int to;
+};
+
// CompilationInfo encapsulates some information known at compile time. It
// is constructed based on the resources available at compile-time.
class CompilationInfo {
@@ -257,6 +263,20 @@
prologue_offset_ = prologue_offset;
}
+ // Adds offset range [from, to) where fp register does not point
+ // to the current frame base. Used in CPU profiler to detect stack
+ // samples where top frame is not set up.
+ inline void AddNoFrameRange(int from, int to) {
+ if (no_frame_ranges_) no_frame_ranges_->Add(OffsetRange(from, to));
+ }
+
+ List<OffsetRange>* ReleaseNoFrameRanges() {
+ List<OffsetRange>* result = no_frame_ranges_;
+ no_frame_ranges_ = NULL;
+ return result;
+ }
+
+
private:
Isolate* isolate_;
@@ -361,6 +381,8 @@
int prologue_offset_;
+ List<OffsetRange>* no_frame_ranges_;
+
// A copy of shared_info()->opt_count() to avoid handle deref
// during graph optimization.
int opt_count_;
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 51d2942..c30d4d4 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -29,6 +29,7 @@
#include "cpu-profiler-inl.h"
+#include "compiler.h"
#include "frames-inl.h"
#include "hashmap.h"
#include "log-inl.h"
@@ -80,7 +81,8 @@
int line_number,
Address start,
unsigned size,
- Address shared) {
+ Address shared,
+ CompilationInfo* info) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
@@ -88,6 +90,9 @@
rec->order = ++enqueue_order_;
rec->start = start;
rec->entry = profiles_->NewCodeEntry(tag, name, resource_name, line_number);
+ if (info) {
+ rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
+ }
rec->size = size;
rec->shared = shared;
events_buffer_.Enqueue(evt_rec);
@@ -323,6 +328,7 @@
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
+ NULL,
NULL);
}
@@ -330,6 +336,7 @@
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
Name* name) {
processor_->CodeCreateEvent(
tag,
@@ -338,13 +345,15 @@
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
- shared->address());
+ shared->address(),
+ info);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
String* source, int line) {
processor_->CodeCreateEvent(
tag,
@@ -353,7 +362,8 @@
line,
code->address(),
code->ExecutableSize(),
- shared->address());
+ shared->address(),
+ info);
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index da7ea6d..2f8479f 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -40,6 +40,7 @@
// Forward declarations.
class CodeEntry;
class CodeMap;
+class CompilationInfo;
class CpuProfile;
class CpuProfilesCollection;
class ProfileGenerator;
@@ -142,7 +143,8 @@
Name* name,
String* resource_name, int line_number,
Address start, unsigned size,
- Address shared);
+ Address shared,
+ CompilationInfo* info);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
const char* name,
Address start, unsigned size);
@@ -227,11 +229,13 @@
Code* code, Name* name);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
- SharedFunctionInfo* shared,
- Name* name);
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
String* source, int line);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, int args_count);
diff --git a/src/d8.cc b/src/d8.cc
index 7ac78cc..b95432e 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -89,38 +89,15 @@
}
-// TODO(rossberg): should replace these by proper uses of HasInstance,
-// once we figure out a good way to make the templates global.
-const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
-const char kArrayMarkerPropName[] = "d8::_is_typed_array_";
-
-
-#define FOR_EACH_STRING(V) \
- V(ArrayBuffer, "ArrayBuffer") \
- V(ArrayBufferMarkerPropName, kArrayBufferMarkerPropName) \
- V(ArrayMarkerPropName, kArrayMarkerPropName) \
- V(buffer, "buffer") \
- V(byteLength, "byteLength") \
- V(byteOffset, "byteOffset") \
- V(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
- V(length, "length")
-
class PerIsolateData {
public:
explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
HandleScope scope(isolate);
-#define INIT_STRING(name, value) \
- name##_string_ = Persistent<String>::New(isolate, String::NewSymbol(value));
- FOR_EACH_STRING(INIT_STRING)
-#undef INIT_STRING
isolate->SetData(this);
}
~PerIsolateData() {
-#define DISPOSE_STRING(name, value) name##_string_.Dispose(isolate_);
- FOR_EACH_STRING(DISPOSE_STRING)
-#undef DISPOSE_STRING
isolate_->SetData(NULL); // Not really needed, just to be sure...
}
@@ -128,13 +105,6 @@
return reinterpret_cast<PerIsolateData*>(isolate->GetData());
}
-#define DEFINE_STRING_GETTER(name, value) \
- static Handle<String> name##_string(Isolate* isolate) { \
- return Handle<String>(*Get(isolate)->name##_string_); \
- }
- FOR_EACH_STRING(DEFINE_STRING_GETTER)
-#undef DEFINE_STRING_GETTER
-
class RealmScope {
public:
explicit RealmScope(PerIsolateData* data);
@@ -153,10 +123,6 @@
Persistent<Context>* realms_;
Persistent<Value> realm_shared_;
-#define DEFINE_MEMBER(name, value) Persistent<String> name##_string_;
- FOR_EACH_STRING(DEFINE_MEMBER)
-#undef DEFINE_MEMBER
-
int RealmFind(Handle<Context> context);
};
@@ -561,565 +527,6 @@
return Undefined(args.GetIsolate());
}
-static int32_t convertToInt(Local<Value> value_in, TryCatch* try_catch) {
- if (value_in->IsInt32()) {
- return value_in->Int32Value();
- }
-
- Local<Value> number = value_in->ToNumber();
- if (try_catch->HasCaught()) return 0;
-
- ASSERT(number->IsNumber());
- Local<Int32> int32 = number->ToInt32();
- if (try_catch->HasCaught() || int32.IsEmpty()) return 0;
-
- int32_t value = int32->Int32Value();
- if (try_catch->HasCaught()) return 0;
-
- return value;
-}
-
-
-static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) {
- int32_t raw_value = convertToInt(value_in, try_catch);
- if (try_catch->HasCaught()) return 0;
-
- if (raw_value < 0) {
- Throw("Array length must not be negative.");
- return 0;
- }
-
- static const int kMaxLength = 0x3fffffff;
-#ifndef V8_SHARED
- ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
-#endif // V8_SHARED
- if (raw_value > static_cast<int32_t>(kMaxLength)) {
- Throw("Array length exceeds maximum length.");
- }
- return raw_value;
-}
-
-
-Handle<Value> Shell::CreateExternalArrayBuffer(Isolate* isolate,
- Handle<Object> buffer,
- int32_t length) {
- static const int32_t kMaxSize = 0x7fffffff;
- // Make sure the total size fits into a (signed) int.
- if (length < 0 || length > kMaxSize) {
- return Throw("ArrayBuffer exceeds maximum size (2G)");
- }
- uint8_t* data = new uint8_t[length];
- if (data == NULL) {
- return Throw("Memory allocation failed");
- }
- memset(data, 0, length);
-
- buffer->SetHiddenValue(
- PerIsolateData::ArrayBufferMarkerPropName_string(isolate), True());
- Persistent<Object> persistent_array =
- Persistent<Object>::New(isolate, buffer);
- persistent_array.MakeWeak(isolate, data, ExternalArrayWeakCallback);
- persistent_array.MarkIndependent(isolate);
- isolate->AdjustAmountOfExternalAllocatedMemory(length);
-
- buffer->SetIndexedPropertiesToExternalArrayData(
- data, v8::kExternalByteArray, length);
- buffer->Set(PerIsolateData::byteLength_string(isolate),
- Int32::New(length, isolate),
- ReadOnly);
-
- return buffer;
-}
-
-
-Handle<Value> Shell::ArrayBuffer(const Arguments& args) {
- if (!args.IsConstructCall()) {
- Handle<Value>* rec_args = new Handle<Value>[args.Length()];
- for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i];
- Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args);
- delete[] rec_args;
- return result;
- }
-
- if (args.Length() == 0) {
- return Throw("ArrayBuffer constructor must have one argument");
- }
- TryCatch try_catch;
- int32_t length = convertToUint(args[0], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- return CreateExternalArrayBuffer(args.GetIsolate(), args.This(), length);
-}
-
-
-Handle<Object> Shell::CreateExternalArray(Isolate* isolate,
- Handle<Object> array,
- Handle<Object> buffer,
- ExternalArrayType type,
- int32_t length,
- int32_t byteLength,
- int32_t byteOffset,
- int32_t element_size) {
- ASSERT(element_size == 1 || element_size == 2 ||
- element_size == 4 || element_size == 8);
- ASSERT(byteLength == length * element_size);
-
- void* data = buffer->GetIndexedPropertiesExternalArrayData();
- ASSERT(data != NULL);
-
- array->SetIndexedPropertiesToExternalArrayData(
- static_cast<uint8_t*>(data) + byteOffset, type, length);
- array->SetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate),
- Int32::New(type, isolate));
- array->Set(PerIsolateData::byteLength_string(isolate),
- Int32::New(byteLength, isolate),
- ReadOnly);
- array->Set(PerIsolateData::byteOffset_string(isolate),
- Int32::New(byteOffset, isolate),
- ReadOnly);
- array->Set(PerIsolateData::length_string(isolate),
- Int32::New(length, isolate),
- ReadOnly);
- array->Set(PerIsolateData::BYTES_PER_ELEMENT_string(isolate),
- Int32::New(element_size, isolate));
- array->Set(PerIsolateData::buffer_string(isolate),
- buffer,
- ReadOnly);
-
- return array;
-}
-
-
-Handle<Value> Shell::CreateExternalArray(const Arguments& args,
- ExternalArrayType type,
- int32_t element_size) {
- Isolate* isolate = args.GetIsolate();
- if (!args.IsConstructCall()) {
- Handle<Value>* rec_args = new Handle<Value>[args.Length()];
- for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i];
- Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args);
- delete[] rec_args;
- return result;
- }
-
- TryCatch try_catch;
- ASSERT(element_size == 1 || element_size == 2 ||
- element_size == 4 || element_size == 8);
-
- // All of the following constructors are supported:
- // TypedArray(unsigned long length)
- // TypedArray(type[] array)
- // TypedArray(TypedArray array)
- // TypedArray(ArrayBuffer buffer,
- // optional unsigned long byteOffset,
- // optional unsigned long length)
- Handle<Object> buffer;
- int32_t length;
- int32_t byteLength;
- int32_t byteOffset;
- bool init_from_array = false;
- if (args.Length() == 0) {
- return Throw("Array constructor must have at least one argument");
- }
- if (args[0]->IsObject() &&
- !args[0]->ToObject()->GetHiddenValue(
- PerIsolateData::ArrayBufferMarkerPropName_string(isolate)).IsEmpty()) {
- // Construct from ArrayBuffer.
- buffer = args[0]->ToObject();
- int32_t bufferLength = convertToUint(
- buffer->Get(PerIsolateData::byteLength_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- if (args.Length() < 2 || args[1]->IsUndefined()) {
- byteOffset = 0;
- } else {
- byteOffset = convertToUint(args[1], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- if (byteOffset > bufferLength) {
- return Throw("byteOffset out of bounds");
- }
- if (byteOffset % element_size != 0) {
- return Throw("byteOffset must be multiple of element size");
- }
- }
-
- if (args.Length() < 3 || args[2]->IsUndefined()) {
- byteLength = bufferLength - byteOffset;
- length = byteLength / element_size;
- if (byteLength % element_size != 0) {
- return Throw("buffer size must be multiple of element size");
- }
- } else {
- length = convertToUint(args[2], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- byteLength = length * element_size;
- if (byteOffset + byteLength > bufferLength) {
- return Throw("length out of bounds");
- }
- }
- } else {
- if (args[0]->IsObject() &&
- args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) {
- // Construct from array.
- Local<Value> value =
- args[0]->ToObject()->Get(PerIsolateData::length_string(isolate));
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- length = convertToUint(value, &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- init_from_array = true;
- } else {
- // Construct from size.
- length = convertToUint(args[0], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- }
- byteLength = length * element_size;
- byteOffset = 0;
-
- Handle<Object> global = Context::GetCurrent()->Global();
- Handle<Value> array_buffer =
- global->Get(PerIsolateData::ArrayBuffer_string(isolate));
- ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction());
- Handle<Value> buffer_args[] = { Uint32::New(byteLength, isolate) };
- Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance(
- 1, buffer_args);
- if (try_catch.HasCaught()) return result;
- buffer = result->ToObject();
- }
-
- Handle<Object> array =
- CreateExternalArray(isolate, args.This(), buffer, type, length,
- byteLength, byteOffset, element_size);
-
- if (init_from_array) {
- Handle<Object> init = args[0]->ToObject();
- for (int i = 0; i < length; ++i) {
- Local<Value> value = init->Get(i);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- array->Set(i, value);
- }
- }
-
- return array;
-}
-
-
-Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) {
- TryCatch try_catch;
-
- if (!args.This()->IsObject()) {
- return Throw("'slice' invoked on non-object receiver");
- }
-
- Isolate* isolate = args.GetIsolate();
- Local<Object> self = args.This();
- Local<Value> marker = self->GetHiddenValue(
- PerIsolateData::ArrayBufferMarkerPropName_string(isolate));
- if (marker.IsEmpty()) {
- return Throw("'slice' invoked on wrong receiver type");
- }
-
- int32_t length = convertToUint(
- self->Get(PerIsolateData::byteLength_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- if (args.Length() == 0) {
- return Throw("'slice' must have at least one argument");
- }
- int32_t begin = convertToInt(args[0], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- if (begin < 0) begin += length;
- if (begin < 0) begin = 0;
- if (begin > length) begin = length;
-
- int32_t end;
- if (args.Length() < 2 || args[1]->IsUndefined()) {
- end = length;
- } else {
- end = convertToInt(args[1], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- if (end < 0) end += length;
- if (end < 0) end = 0;
- if (end > length) end = length;
- if (end < begin) end = begin;
- }
-
- Local<Function> constructor = Local<Function>::Cast(self->GetConstructor());
- Handle<Value> new_args[] = { Uint32::New(end - begin, isolate) };
- Handle<Value> result = constructor->NewInstance(1, new_args);
- if (try_catch.HasCaught()) return result;
- Handle<Object> buffer = result->ToObject();
- uint8_t* dest =
- static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData());
- uint8_t* src = begin + static_cast<uint8_t*>(
- self->GetIndexedPropertiesExternalArrayData());
- memcpy(dest, src, end - begin);
-
- return buffer;
-}
-
-
-Handle<Value> Shell::ArraySubArray(const Arguments& args) {
- TryCatch try_catch;
-
- if (!args.This()->IsObject()) {
- return Throw("'subarray' invoked on non-object receiver");
- }
-
- Isolate* isolate = args.GetIsolate();
- Local<Object> self = args.This();
- Local<Value> marker =
- self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate));
- if (marker.IsEmpty()) {
- return Throw("'subarray' invoked on wrong receiver type");
- }
-
- Handle<Object> buffer =
- self->Get(PerIsolateData::buffer_string(isolate))->ToObject();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t length = convertToUint(
- self->Get(PerIsolateData::length_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t byteOffset = convertToUint(
- self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t element_size = convertToUint(
- self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- if (args.Length() == 0) {
- return Throw("'subarray' must have at least one argument");
- }
- int32_t begin = convertToInt(args[0], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- if (begin < 0) begin += length;
- if (begin < 0) begin = 0;
- if (begin > length) begin = length;
-
- int32_t end;
- if (args.Length() < 2 || args[1]->IsUndefined()) {
- end = length;
- } else {
- end = convertToInt(args[1], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- if (end < 0) end += length;
- if (end < 0) end = 0;
- if (end > length) end = length;
- if (end < begin) end = begin;
- }
-
- length = end - begin;
- byteOffset += begin * element_size;
-
- Local<Function> constructor = Local<Function>::Cast(self->GetConstructor());
- Handle<Value> construct_args[] = {
- buffer, Uint32::New(byteOffset, isolate), Uint32::New(length, isolate)
- };
- return constructor->NewInstance(3, construct_args);
-}
-
-
-Handle<Value> Shell::ArraySet(const Arguments& args) {
- TryCatch try_catch;
-
- if (!args.This()->IsObject()) {
- return Throw("'set' invoked on non-object receiver");
- }
-
- Isolate* isolate = args.GetIsolate();
- Local<Object> self = args.This();
- Local<Value> marker =
- self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate));
- if (marker.IsEmpty()) {
- return Throw("'set' invoked on wrong receiver type");
- }
- int32_t length = convertToUint(
- self->Get(PerIsolateData::length_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t element_size = convertToUint(
- self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- if (args.Length() == 0) {
- return Throw("'set' must have at least one argument");
- }
- if (!args[0]->IsObject() ||
- !args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) {
- return Throw("'set' invoked with non-array argument");
- }
- Handle<Object> source = args[0]->ToObject();
- int32_t source_length = convertToUint(
- source->Get(PerIsolateData::length_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- int32_t offset;
- if (args.Length() < 2 || args[1]->IsUndefined()) {
- offset = 0;
- } else {
- offset = convertToUint(args[1], &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- }
- if (offset + source_length > length) {
- return Throw("offset or source length out of bounds");
- }
-
- int32_t source_element_size;
- if (source->GetHiddenValue(
- PerIsolateData::ArrayMarkerPropName_string(isolate)).IsEmpty()) {
- source_element_size = 0;
- } else {
- source_element_size = convertToUint(
- source->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)),
- &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- }
-
- if (element_size == source_element_size &&
- self->GetConstructor()->StrictEquals(source->GetConstructor())) {
- // Use memmove on the array buffers.
- Handle<Object> buffer =
- self->Get(PerIsolateData::buffer_string(isolate))->ToObject();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- Handle<Object> source_buffer =
- source->Get(PerIsolateData::buffer_string(isolate))->ToObject();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t byteOffset = convertToUint(
- self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t source_byteOffset = convertToUint(
- source->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>(
- buffer->GetIndexedPropertiesExternalArrayData());
- uint8_t* src = source_byteOffset + static_cast<uint8_t*>(
- source_buffer->GetIndexedPropertiesExternalArrayData());
- memmove(dest, src, source_length * element_size);
- } else if (source_element_size == 0) {
- // Source is not a typed array, copy element-wise sequentially.
- for (int i = 0; i < source_length; ++i) {
- self->Set(offset + i, source->Get(i));
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- }
- } else {
- // Need to copy element-wise to make the right conversions.
- Handle<Object> buffer =
- self->Get(PerIsolateData::buffer_string(isolate))->ToObject();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- Handle<Object> source_buffer =
- source->Get(PerIsolateData::buffer_string(isolate))->ToObject();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- if (buffer->StrictEquals(source_buffer)) {
- // Same backing store, need to handle overlap correctly.
- // This gets a bit tricky in the case of different element sizes
- // (which, of course, is extremely unlikely to ever occur in practice).
- int32_t byteOffset = convertToUint(
- self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
- int32_t source_byteOffset = convertToUint(
- source->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch);
- if (try_catch.HasCaught()) return try_catch.ReThrow();
-
- // Copy as much as we can from left to right.
- int i = 0;
- int32_t next_dest_offset = byteOffset + (offset + 1) * element_size;
- int32_t next_src_offset = source_byteOffset + source_element_size;
- while (i < length && next_dest_offset <= next_src_offset) {
- self->Set(offset + i, source->Get(i));
- ++i;
- next_dest_offset += element_size;
- next_src_offset += source_element_size;
- }
- // Of what's left, copy as much as we can from right to left.
- int j = length - 1;
- int32_t dest_offset = byteOffset + (offset + j) * element_size;
- int32_t src_offset = source_byteOffset + j * source_element_size;
- while (j >= i && dest_offset >= src_offset) {
- self->Set(offset + j, source->Get(j));
- --j;
- dest_offset -= element_size;
- src_offset -= source_element_size;
- }
- // There can be at most 8 entries left in the middle that need buffering
- // (because the largest element_size is 8 times the smallest).
- ASSERT(j+1 - i <= 8);
- Handle<Value> temp[8];
- for (int k = i; k <= j; ++k) {
- temp[k - i] = source->Get(k);
- }
- for (int k = i; k <= j; ++k) {
- self->Set(offset + k, temp[k - i]);
- }
- } else {
- // Different backing stores, safe to copy element-wise sequentially.
- for (int i = 0; i < source_length; ++i)
- self->Set(offset + i, source->Get(i));
- }
- }
-
- return Undefined(args.GetIsolate());
-}
-
-
-void Shell::ExternalArrayWeakCallback(v8::Isolate* isolate,
- Persistent<Object>* object,
- uint8_t* data) {
- HandleScope scope(isolate);
- int32_t length = (*object)->Get(
- PerIsolateData::byteLength_string(isolate))->Uint32Value();
- isolate->AdjustAmountOfExternalAllocatedMemory(-length);
- delete[] data;
- object->Dispose(isolate);
-}
-
-
-Handle<Value> Shell::Int8Array(const Arguments& args) {
- return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
-}
-
-
-Handle<Value> Shell::Uint8Array(const Arguments& args) {
- return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
-}
-
-
-Handle<Value> Shell::Int16Array(const Arguments& args) {
- return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
-}
-
-
-Handle<Value> Shell::Uint16Array(const Arguments& args) {
- return CreateExternalArray(
- args, kExternalUnsignedShortArray, sizeof(uint16_t));
-}
-
-
-Handle<Value> Shell::Int32Array(const Arguments& args) {
- return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
-}
-
-
-Handle<Value> Shell::Uint32Array(const Arguments& args) {
- return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
-}
-
-
-Handle<Value> Shell::Float32Array(const Arguments& args) {
- return CreateExternalArray(
- args, kExternalFloatArray, sizeof(float)); // NOLINT
-}
-
-
-Handle<Value> Shell::Float64Array(const Arguments& args) {
- return CreateExternalArray(
- args, kExternalDoubleArray, sizeof(double)); // NOLINT
-}
-
-
-Handle<Value> Shell::Uint8ClampedArray(const Arguments& args) {
- return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
-}
-
Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value();
@@ -1412,26 +819,6 @@
#endif
-Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate(
- InvocationCallback fun) {
- Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun);
- Local<Template> proto_template = buffer_template->PrototypeTemplate();
- proto_template->Set(String::New("slice"),
- FunctionTemplate::New(ArrayBufferSlice));
- return buffer_template;
-}
-
-
-Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) {
- Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun);
- Local<Template> proto_template = array_template->PrototypeTemplate();
- proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet));
- proto_template->Set(String::New("subarray"),
- FunctionTemplate::New(ArraySubArray));
- return array_template;
-}
-
-
Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
global_template->Set(String::New("print"), FunctionTemplate::New(Print));
@@ -1469,36 +856,6 @@
RealmSharedGet, RealmSharedSet);
global_template->Set(String::New("Realm"), realm_template);
- // Bind the handlers for external arrays.
-#ifndef V8_SHARED
- if (!i::FLAG_harmony_typed_arrays) {
-#endif // V8_SHARED
- PropertyAttribute attr =
- static_cast<PropertyAttribute>(ReadOnly | DontDelete);
- global_template->Set(PerIsolateData::ArrayBuffer_string(isolate),
- CreateArrayBufferTemplate(ArrayBuffer), attr);
- global_template->Set(String::New("Int8Array"),
- CreateArrayTemplate(Int8Array), attr);
- global_template->Set(String::New("Uint8Array"),
- CreateArrayTemplate(Uint8Array), attr);
- global_template->Set(String::New("Int16Array"),
- CreateArrayTemplate(Int16Array), attr);
- global_template->Set(String::New("Uint16Array"),
- CreateArrayTemplate(Uint16Array), attr);
- global_template->Set(String::New("Int32Array"),
- CreateArrayTemplate(Int32Array), attr);
- global_template->Set(String::New("Uint32Array"),
- CreateArrayTemplate(Uint32Array), attr);
- global_template->Set(String::New("Float32Array"),
- CreateArrayTemplate(Float32Array), attr);
- global_template->Set(String::New("Float64Array"),
- CreateArrayTemplate(Float64Array), attr);
- global_template->Set(String::New("Uint8ClampedArray"),
- CreateArrayTemplate(Uint8ClampedArray), attr);
-#ifndef V8_SHARED
- }
-#endif // V8_SHARED
-
#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
AddOSMethods(os_templ);
@@ -1705,20 +1062,9 @@
if (data == NULL) {
return Throw("Error reading file");
}
- Isolate* isolate = args.GetIsolate();
- Handle<Object> buffer = Object::New();
- buffer->SetHiddenValue(
- PerIsolateData::ArrayBufferMarkerPropName_string(isolate), True());
- Persistent<Object> persistent_buffer =
- Persistent<Object>::New(isolate, buffer);
- persistent_buffer.MakeWeak(isolate, data, ExternalArrayWeakCallback);
- persistent_buffer.MarkIndependent(isolate);
- isolate->AdjustAmountOfExternalAllocatedMemory(length);
-
- buffer->SetIndexedPropertiesToExternalArrayData(
- data, kExternalUnsignedByteArray, length);
- buffer->Set(PerIsolateData::byteLength_string(isolate),
- Int32::New(static_cast<int32_t>(length), isolate), ReadOnly);
+ Handle<v8::ArrayBuffer> buffer = ArrayBuffer::New(length);
+ memcpy(buffer->Data(), data, length);
+ delete[] data;
return buffer;
}
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 1bf27f1..26410e9 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -505,14 +505,11 @@
const char* Deoptimizer::MessageFor(BailoutType type) {
switch (type) {
- case EAGER:
- case SOFT:
- case LAZY:
- return "DEOPT";
- case DEBUGGER:
- return "DEOPT FOR DEBUGGER";
- case OSR:
- return "OSR";
+ case EAGER: return "eager";
+ case SOFT: return "soft";
+ case LAZY: return "lazy";
+ case DEBUGGER: return "debugger";
+ case OSR: return "OSR";
}
UNREACHABLE();
return NULL;
@@ -561,7 +558,6 @@
? StackFrame::STUB
: StackFrame::JAVA_SCRIPT;
trace_ = TraceEnabledFor(type, frame_type);
- if (trace_) Trace();
ASSERT(HEAP->allow_allocation(false));
unsigned size = ComputeInputFrameSize();
input_ = new(size) FrameDescription(size, function);
@@ -601,19 +597,6 @@
}
-void Deoptimizer::Trace() {
- PrintF("**** %s: ", Deoptimizer::MessageFor(bailout_type_));
- PrintFunctionName();
- PrintF(" at id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
- bailout_id_,
- reinterpret_cast<intptr_t>(from_),
- fp_to_sp_delta_ - (2 * kPointerSize));
- if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
- compiled_code_->PrintDeoptLocation(bailout_id_);
- }
-}
-
-
void Deoptimizer::PrintFunctionName() {
if (function_->IsJSFunction()) {
function_->PrintName();
@@ -723,11 +706,14 @@
// Print some helpful diagnostic information.
int64_t start = OS::Ticks();
if (trace_) {
- PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
- (bailout_type_ == LAZY ? " (lazy)" : ""),
+ PrintF("[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
+ MessageFor(bailout_type_),
reinterpret_cast<intptr_t>(function_));
PrintFunctionName();
- PrintF(" @%d]\n", bailout_id_);
+ PrintF(" @%d, FP to SP delta: %d]\n", bailout_id_, fp_to_sp_delta_);
+ if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
+ compiled_code_->PrintDeoptLocation(bailout_id_);
+ }
}
// Determine basic deoptimization information. The optimized frame is
@@ -804,11 +790,13 @@
double ms = static_cast<double>(OS::Ticks() - start) / 1000;
int index = output_count_ - 1; // Index of the topmost frame.
JSFunction* function = output_[index]->GetFunction();
- PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
+ PrintF("[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
+ MessageFor(bailout_type_),
reinterpret_cast<intptr_t>(function));
- if (function != NULL) function->PrintName();
- PrintF(" => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
+ PrintFunctionName();
+ PrintF(" @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
" took %0.3f ms]\n",
+ bailout_id_,
node_id.ToInt(),
output_[index]->GetPc(),
FullCodeGenerator::State2String(
@@ -820,6 +808,193 @@
}
+void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
+ int frame_index) {
+ BailoutId node_id = BailoutId(iterator->Next());
+ JSFunction* function;
+ if (frame_index != 0) {
+ function = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ } else {
+ int closure_id = iterator->Next();
+ USE(closure_id);
+ ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
+ function = function_;
+ }
+ unsigned height = iterator->Next();
+ unsigned height_in_bytes = height * kPointerSize;
+ if (trace_) {
+ PrintF(" translating ");
+ function->PrintName();
+ PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
+ }
+
+ // The 'fixed' part of the frame consists of the incoming parameters and
+ // the part described by JavaScriptFrameConstants.
+ unsigned fixed_frame_size = ComputeFixedSize(function);
+ unsigned input_frame_size = input_->GetFrameSize();
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, function);
+ output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
+
+ bool is_bottommost = (0 == frame_index);
+ bool is_topmost = (output_count_ - 1 == frame_index);
+ ASSERT(frame_index >= 0 && frame_index < output_count_);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address for the bottommost output frame can be computed from
+ // the input frame pointer and the output frame's height. For all
+ // subsequent output frames, it can be computed from the previous one's
+ // top address and the current frame's size.
+ Register fp_reg = JavaScriptFrame::fp_register();
+ intptr_t top_address;
+ if (is_bottommost) {
+ // Determine whether the input frame contains alignment padding.
+ has_alignment_padding_ = HasAlignmentPadding(function) ? 1 : 0;
+ // 2 = context and function in the frame.
+ // If the optimized frame had alignment padding, adjust the frame pointer
+ // to point to the new position of the old frame pointer after padding
+ // is removed. Subtract 2 * kPointerSize for the context and function slots.
+ top_address = input_->GetRegister(fp_reg.code()) - (2 * kPointerSize) -
+ height_in_bytes + has_alignment_padding_ * kPointerSize;
+ } else {
+ top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ }
+ output_frame->SetTop(top_address);
+
+ // Compute the incoming parameter translation.
+ int parameter_count = function->shared()->formal_parameter_count() + 1;
+ unsigned output_offset = output_frame_size;
+ unsigned input_offset = input_frame_size;
+ for (int i = 0; i < parameter_count; ++i) {
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+ }
+ input_offset -= (parameter_count * kPointerSize);
+
+ // There are no translation commands for the caller's pc and fp, the
+ // context, and the function. Synthesize their values and set them up
+ // explicitly.
+ //
+ // The caller's pc for the bottommost output frame is the same as in the
+ // input frame. For all subsequent output frames, it can be read from the
+ // previous one. This frame's pc can be computed from the non-optimized
+ // function code and AST id of the bailout.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ intptr_t value;
+ if (is_bottommost) {
+ value = input_->GetFrameSlot(input_offset);
+ } else {
+ value = output_[frame_index - 1]->GetPc();
+ }
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; caller's pc\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // The caller's frame pointer for the bottommost output frame is the same
+ // as in the input frame. For all subsequent output frames, it can be
+ // read from the previous one. Also compute and set this frame's frame
+ // pointer.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ if (is_bottommost) {
+ value = input_->GetFrameSlot(input_offset);
+ } else {
+ value = output_[frame_index - 1]->GetFp();
+ }
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ ASSERT(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
+ has_alignment_padding_ * kPointerSize) == fp_value);
+ output_frame->SetFp(fp_value);
+ if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+ ASSERT(!is_bottommost || !has_alignment_padding_ ||
+ (fp_value & kPointerSize) != 0);
+
+ // For the bottommost output frame the context can be gotten from the input
+ // frame. For all subsequent output frames it can be gotten from the function
+ // so long as we don't inline functions that need local contexts.
+ Register context_reg = JavaScriptFrame::context_register();
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ if (is_bottommost) {
+ value = input_->GetFrameSlot(input_offset);
+ } else {
+ value = reinterpret_cast<intptr_t>(function->context());
+ }
+ output_frame->SetFrameSlot(output_offset, value);
+ output_frame->SetContext(value);
+ if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR "; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // The function was mentioned explicitly in the BEGIN_FRAME.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(function);
+ // The function for the bottommost output frame should also agree with the
+ // input frame.
+ ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR "; function\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Translate the rest of the frame.
+ for (unsigned i = 0; i < height; ++i) {
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+ }
+ ASSERT(0 == output_offset);
+
+ // Compute this frame's PC, state, and continuation.
+ Code* non_optimized_code = function->shared()->code();
+ FixedArray* raw_data = non_optimized_code->deoptimization_data();
+ DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
+ Address start = non_optimized_code->instruction_start();
+ unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
+ unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
+ intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
+ output_frame->SetPc(pc_value);
+
+ FullCodeGenerator::State state =
+ FullCodeGenerator::StateField::decode(pc_and_state);
+ output_frame->SetState(Smi::FromInt(state));
+
+ // Set the continuation for the topmost frame.
+ if (is_topmost && bailout_type_ != DEBUGGER) {
+ Builtins* builtins = isolate_->builtins();
+ Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
+ if (bailout_type_ == LAZY) {
+ continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
+ } else if (bailout_type_ == SOFT) {
+ continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
+ } else {
+ ASSERT(bailout_type_ == EAGER);
+ }
+ output_frame->SetContinuation(
+ reinterpret_cast<intptr_t>(continuation->entry()));
+ }
+}
+
+
void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
int frame_index) {
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index d4d3c48..c1b3a9d 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -335,7 +335,6 @@
int fp_to_sp_delta,
Code* optimized_code);
Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
- void Trace();
void PrintFunctionName();
void DeleteFrameDescriptions();
@@ -407,6 +406,10 @@
// from the input frame's double registers.
void CopyDoubleRegisters(FrameDescription* output_frame);
+ // Determines whether the input frame contains alignment padding by looking
+ // at the dynamic alignment state slot inside the frame.
+ bool HasAlignmentPadding(JSFunction* function);
+
Isolate* isolate_;
JSFunction* function_;
Code* compiled_code_;
diff --git a/src/factory.h b/src/factory.h
index 5e89708..233b3b0 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -266,10 +266,12 @@
PretenureFlag pretenure = NOT_TENURED);
Handle<Object> NewNumberFromUint(uint32_t value,
PretenureFlag pretenure = NOT_TENURED);
-
+ inline Handle<Object> NewNumberFromSize(size_t value,
+ PretenureFlag pretenure = NOT_TENURED);
Handle<HeapNumber> NewHeapNumber(double value,
PretenureFlag pretenure = NOT_TENURED);
+
// These objects are used by the api to create env-independent data
// structures in the heap.
Handle<JSObject> NewNeanderObject();
@@ -539,6 +541,18 @@
};
+Handle<Object> Factory::NewNumberFromSize(size_t value,
+ PretenureFlag pretenure) {
+ if (Smi::IsValid(static_cast<intptr_t>(value))) {
+ return Handle<Object>(Smi::FromIntptr(static_cast<intptr_t>(value)),
+ isolate());
+ } else {
+ return NewNumber(static_cast<double>(value), pretenure);
+ }
+}
+
+
+
} } // namespace v8::internal
#endif // V8_FACTORY_H_
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 9b1ed1d..58f29b4 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -207,7 +207,6 @@
DEFINE_bool(crankshaft, true, "use crankshaft")
DEFINE_string(hydrogen_filter, "", "optimization filter")
DEFINE_bool(use_range, true, "use hydrogen range analysis")
-DEFINE_bool(eliminate_dead_phis, true, "eliminate dead phis")
DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
DEFINE_bool(use_inlining, true, "use function inlining")
@@ -269,6 +268,8 @@
"info, not JSFunction itself")
DEFINE_bool(cache_optimized_code, true,
"cache optimized code for closures")
+DEFINE_bool(flush_optimized_code_cache, true,
+ "flushes the cache of optimized code for closures on every GC")
DEFINE_bool(inline_construct, true, "inline constructor calls")
DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
DEFINE_bool(inline_accessors, true, "inline JavaScript accessors")
@@ -465,6 +466,7 @@
"flush code that we expect not to use again (during full gc)")
DEFINE_bool(flush_code_incrementally, true,
"flush code that we expect not to use again (incrementally)")
+DEFINE_bool(trace_code_flushing, false, "trace code flushing progress")
DEFINE_bool(age_code, true,
"track un-executed functions to age code and flush only "
"old code")
diff --git a/src/frames.h b/src/frames.h
index 3c44f5e..f09c24a 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -584,6 +584,10 @@
// Build a list with summaries for this frame including all inlined frames.
virtual void Summarize(List<FrameSummary>* frames);
+ // Architecture-specific register description.
+ static Register fp_register();
+ static Register context_register();
+
static JavaScriptFrame* cast(StackFrame* frame) {
ASSERT(frame->is_java_script());
return static_cast<JavaScriptFrame*>(frame);
diff --git a/src/heap.cc b/src/heap.cc
index 6a6afc0..a69c539 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -120,7 +120,6 @@
new_space_high_promotion_mode_active_(false),
old_gen_promotion_limit_(kMinimumPromotionLimit),
old_gen_allocation_limit_(kMinimumAllocationLimit),
- old_gen_limit_factor_(1),
size_of_old_gen_at_last_old_space_gc_(0),
external_allocation_limit_(0),
amount_of_external_allocated_memory_(0),
@@ -912,26 +911,11 @@
// Perform mark-sweep with optional compaction.
MarkCompact(tracer);
sweep_generation_++;
- bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
- IsStableOrIncreasingSurvivalTrend();
UpdateSurvivalRateTrend(start_new_space_size);
size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
- if (high_survival_rate_during_scavenges &&
- IsStableOrIncreasingSurvivalTrend()) {
- // Stable high survival rates of young objects both during partial and
- // full collection indicate that mutator is either building or modifying
- // a structure with a long lifetime.
- // In this case we aggressively raise old generation memory limits to
- // postpone subsequent mark-sweep collection and thus trade memory
- // space for the mutation speed.
- old_gen_limit_factor_ = 2;
- } else {
- old_gen_limit_factor_ = 1;
- }
-
old_gen_promotion_limit_ =
OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
old_gen_allocation_limit_ =
@@ -2517,6 +2501,54 @@
}
set_external_double_array_map(Map::cast(obj));
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalByteArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_byte_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj =
+ AllocateEmptyExternalArray(kExternalUnsignedByteArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_unsigned_byte_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalShortArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_short_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(
+ kExternalUnsignedShortArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_unsigned_short_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalIntArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_int_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj =
+ AllocateEmptyExternalArray(kExternalUnsignedIntArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_unsigned_int_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalFloatArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_float_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalDoubleArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_double_array(ExternalArray::cast(obj));
+
+ { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalPixelArray);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_empty_external_pixel_array(ExternalArray::cast(obj));
+
{ MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
@@ -3248,6 +3280,40 @@
}
}
+Heap::RootListIndex Heap::RootIndexForEmptyExternalArray(
+ ElementsKind elementsKind) {
+ switch (elementsKind) {
+ case EXTERNAL_BYTE_ELEMENTS:
+ return kEmptyExternalByteArrayRootIndex;
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ return kEmptyExternalUnsignedByteArrayRootIndex;
+ case EXTERNAL_SHORT_ELEMENTS:
+ return kEmptyExternalShortArrayRootIndex;
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ return kEmptyExternalUnsignedShortArrayRootIndex;
+ case EXTERNAL_INT_ELEMENTS:
+ return kEmptyExternalIntArrayRootIndex;
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ return kEmptyExternalUnsignedIntArrayRootIndex;
+ case EXTERNAL_FLOAT_ELEMENTS:
+ return kEmptyExternalFloatArrayRootIndex;
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ return kEmptyExternalDoubleArrayRootIndex;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ return kEmptyExternalPixelArrayRootIndex;
+ default:
+ UNREACHABLE();
+ return kUndefinedValueRootIndex;
+ }
+}
+
+ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) {
+ return ExternalArray::cast(
+ roots_[RootIndexForEmptyExternalArray(map->elements_kind())]);
+}
+
+
+
MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
// We need to distinguish the minus zero value and this cannot be
@@ -4252,7 +4318,8 @@
InitializeJSObjectFromMap(JSObject::cast(obj),
FixedArray::cast(properties),
map);
- ASSERT(JSObject::cast(obj)->HasFastElements());
+ ASSERT(JSObject::cast(obj)->HasFastElements() ||
+ JSObject::cast(obj)->HasExternalArrayElements());
return obj;
}
@@ -5216,6 +5283,10 @@
return result;
}
+MaybeObject* Heap::AllocateEmptyExternalArray(ExternalArrayType array_type) {
+ return AllocateExternalArray(0, array_type, NULL, TENURED);
+}
+
MaybeObject* Heap::AllocateRawFixedArray(int length) {
if (length < 0 || length > FixedArray::kMaxLength) {
@@ -5895,7 +5966,6 @@
old_gen_promotion_limit_);
PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
old_gen_allocation_limit_);
- PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
PrintF("\n");
PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles(isolate_));
diff --git a/src/heap.h b/src/heap.h
index add42c0..b24b0b3 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -128,7 +128,6 @@
V(Map, short_external_ascii_string_map, ShortExternalAsciiStringMap) \
V(Map, undetectable_string_map, UndetectableStringMap) \
V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
- V(Map, external_pixel_array_map, ExternalPixelArrayMap) \
V(Map, external_byte_array_map, ExternalByteArrayMap) \
V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
V(Map, external_short_array_map, ExternalShortArrayMap) \
@@ -137,6 +136,21 @@
V(Map, external_unsigned_int_array_map, ExternalUnsignedIntArrayMap) \
V(Map, external_float_array_map, ExternalFloatArrayMap) \
V(Map, external_double_array_map, ExternalDoubleArrayMap) \
+ V(Map, external_pixel_array_map, ExternalPixelArrayMap) \
+ V(ExternalArray, empty_external_byte_array, \
+ EmptyExternalByteArray) \
+ V(ExternalArray, empty_external_unsigned_byte_array, \
+ EmptyExternalUnsignedByteArray) \
+ V(ExternalArray, empty_external_short_array, EmptyExternalShortArray) \
+ V(ExternalArray, empty_external_unsigned_short_array, \
+ EmptyExternalUnsignedShortArray) \
+ V(ExternalArray, empty_external_int_array, EmptyExternalIntArray) \
+ V(ExternalArray, empty_external_unsigned_int_array, \
+ EmptyExternalUnsignedIntArray) \
+ V(ExternalArray, empty_external_float_array, EmptyExternalFloatArray) \
+ V(ExternalArray, empty_external_double_array, EmptyExternalDoubleArray) \
+ V(ExternalArray, empty_external_pixel_array, \
+ EmptyExternalPixelArray) \
V(Map, non_strict_arguments_elements_map, NonStrictArgumentsElementsMap) \
V(Map, function_context_map, FunctionContextMap) \
V(Map, catch_context_map, CatchContextMap) \
@@ -273,7 +287,11 @@
V(minus_infinity_string, "-Infinity") \
V(hidden_stack_trace_string, "v8::hidden_stack_trace") \
V(query_colon_string, "(?:)") \
- V(Generator_string, "Generator")
+ V(Generator_string, "Generator") \
+ V(send_string, "send") \
+ V(throw_string, "throw") \
+ V(done_string, "done") \
+ V(value_string, "value")
// Forward declarations.
class GCTracer;
@@ -1567,7 +1585,11 @@
intptr_t limit =
Max(old_gen_size + old_gen_size / divisor, kMinimumPromotionLimit);
limit += new_space_.Capacity();
- limit *= old_gen_limit_factor_;
+ // TODO(hpayer): Can be removed when when pretenuring is supported for all
+ // allocation sites.
+ if (IsHighSurvivalRate() && IsStableOrIncreasingSurvivalTrend()) {
+ limit *= 2;
+ }
intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2;
return Min(limit, halfway_to_the_max);
}
@@ -1578,7 +1600,11 @@
intptr_t limit =
Max(old_gen_size + old_gen_size / divisor, kMinimumAllocationLimit);
limit += new_space_.Capacity();
- limit *= old_gen_limit_factor_;
+ // TODO(hpayer): Can be removed when when pretenuring is supported for all
+ // allocation sites.
+ if (IsHighSurvivalRate() && IsStableOrIncreasingSurvivalTrend()) {
+ limit *= 2;
+ }
intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2;
return Min(limit, halfway_to_the_max);
}
@@ -1626,6 +1652,9 @@
RootListIndex RootIndexForExternalArrayType(
ExternalArrayType array_type);
+ RootListIndex RootIndexForEmptyExternalArray(ElementsKind kind);
+ ExternalArray* EmptyExternalArrayForMap(Map* map);
+
void RecordStats(HeapStats* stats, bool take_snapshot = false);
// Copy block of memory from src to dst. Size of block should be aligned
@@ -1998,10 +2027,6 @@
// every allocation in large object space.
intptr_t old_gen_allocation_limit_;
- // Sometimes the heuristics dictate that those limits are increased. This
- // variable records that fact.
- int old_gen_limit_factor_;
-
// Used to adjust the limits that control the timing of the next GC.
intptr_t size_of_old_gen_at_last_old_space_gc_;
@@ -2140,6 +2165,10 @@
// Allocate empty fixed array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();
+ // Allocate empty external array of given type.
+ MUST_USE_RESULT MaybeObject* AllocateEmptyExternalArray(
+ ExternalArrayType array_type);
+
// Allocate empty fixed double array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 78e1229..b747387 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -650,7 +650,6 @@
void HValue::DeleteAndReplaceWith(HValue* other) {
// We replace all uses first, so Delete can assert that there are none.
if (other != NULL) ReplaceAllUsesWith(other);
- ASSERT(HasNoUses());
Kill();
DeleteFromGraph();
}
@@ -807,6 +806,14 @@
}
+void HInstruction::PrintDataTo(StringStream *stream) {
+ for (int i = 0; i < OperandCount(); ++i) {
+ if (i > 0) stream->Add(" ");
+ OperandAt(i)->PrintNameTo(stream);
+ }
+}
+
+
void HInstruction::PrintMnemonicTo(StringStream* stream) {
stream->Add("%s ", Mnemonic());
}
@@ -1254,14 +1261,6 @@
}
-void HIsNilAndBranch::PrintDataTo(StringStream* stream) {
- value()->PrintNameTo(stream);
- stream->Add(kind() == kStrictEquality ? " === " : " == ");
- stream->Add(nil() == kNullValue ? "null" : "undefined");
- HControlInstruction::PrintDataTo(stream);
-}
-
-
void HReturn::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
stream->Add(" (pop ");
@@ -1916,9 +1915,7 @@
int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses());
- stream->Add("%s%s",
- is_live() ? "_live" : "",
- IsConvertibleToInteger() ? "" : "_ncti");
+ if (!IsConvertibleToInteger()) stream->Add("_ncti");
PrintRangeTo(stream);
PrintTypeTo(stream);
stream->Add("]");
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index a290628..d06e318 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -103,6 +103,7 @@
V(CompareConstantEqAndBranch) \
V(Constant) \
V(Context) \
+ V(DebugBreak) \
V(DeclareGlobals) \
V(DeleteProperty) \
V(Deoptimize) \
@@ -127,7 +128,6 @@
V(InstanceSize) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
- V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
@@ -794,6 +794,7 @@
kDeoptimizeOnUndefined,
kIsArguments,
kTruncatingToInt32,
+ // Set after an instruction is killed.
kIsDead,
// Instructions that are allowed to produce full range unsigned integer
// values are marked with kUint32 flag. If arithmetic shift or a load from
@@ -809,6 +810,8 @@
// has processed this instruction.
kIDefsProcessingDone,
kHasNoObservableSideEffects,
+ // Indicates the instruction is live during dead code elimination.
+ kIsLive,
kLastFlag = kIDefsProcessingDone
};
@@ -1071,8 +1074,9 @@
UNREACHABLE();
}
- bool IsDead() const {
- return HasNoUses() && !HasObservableSideEffects() && IsDeletable();
+ // Check if this instruction has some reason that prevents elimination.
+ bool CannotBeEliminated() const {
+ return HasObservableSideEffects() || !IsDeletable();
}
#ifdef DEBUG
@@ -1247,7 +1251,7 @@
HInstruction* previous() const { return previous_; }
virtual void PrintTo(StringStream* stream);
- virtual void PrintDataTo(StringStream* stream) { }
+ virtual void PrintDataTo(StringStream* stream);
bool IsLinked() const { return block() != NULL; }
void Unlink();
@@ -1460,6 +1464,17 @@
};
+// Inserts an int3/stop break instruction for debugging purposes.
+class HDebugBreak: public HTemplateInstruction<0> {
+ public:
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
+};
+
+
class HDeoptimize: public HControlInstruction {
public:
HDeoptimize(int environment_length, Zone* zone)
@@ -2969,7 +2984,6 @@
: inputs_(2, zone),
merged_index_(merged_index),
phi_id_(-1),
- is_live_(false),
is_convertible_to_integer_(true) {
for (int i = 0; i < Representation::kNumRepresentations; i++) {
non_phi_uses_[i] = 0;
@@ -2994,7 +3008,7 @@
void AddInput(HValue* value);
bool HasRealUses();
- bool IsReceiver() { return merged_index_ == 0; }
+ bool IsReceiver() const { return merged_index_ == 0; }
int merged_index() const { return merged_index_; }
@@ -3029,8 +3043,6 @@
return indirect_uses_[Representation::kDouble];
}
int phi_id() { return phi_id_; }
- bool is_live() { return is_live_; }
- void set_is_live(bool b) { is_live_ = b; }
static HPhi* cast(HValue* value) {
ASSERT(value->IsPhi());
@@ -3062,6 +3074,9 @@
void SimplifyConstantInputs();
+ // TODO(titzer): we can't eliminate the receiver for generating backtraces
+ virtual bool IsDeletable() const { return !IsReceiver(); }
+
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -3080,7 +3095,6 @@
int non_phi_uses_[Representation::kNumRepresentations];
int indirect_uses_[Representation::kNumRepresentations];
int phi_id_;
- bool is_live_;
bool is_convertible_to_integer_;
};
@@ -3921,31 +3935,6 @@
};
-class HIsNilAndBranch: public HUnaryControlInstruction {
- public:
- HIsNilAndBranch(HValue* value, EqualityKind kind, NilValue nil)
- : HUnaryControlInstruction(value, NULL, NULL), kind_(kind), nil_(nil) { }
-
- EqualityKind kind() const { return kind_; }
- NilValue nil() const { return nil_; }
-
- virtual void PrintDataTo(StringStream* stream);
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
- virtual Representation observed_input_representation(int index) {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch)
-
- private:
- EqualityKind kind_;
- NilValue nil_;
-};
-
-
class HIsObjectAndBranch: public HUnaryControlInstruction {
public:
explicit HIsObjectAndBranch(HValue* value)
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 34162ef..a97e083 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -104,7 +104,6 @@
void HBasicBlock::RemovePhi(HPhi* phi) {
ASSERT(phi->block() == this);
ASSERT(phis_.Contains(phi));
- ASSERT(phi->HasNoUses() || !phi->is_live());
phi->Kill();
phis_.RemoveElement(phi);
phi->SetBlock(NULL);
@@ -1813,27 +1812,27 @@
HIfContinuation* continuation) {
IfBuilder if_nil(this, position);
bool needs_or = false;
- if ((types & CompareNilICStub::kCompareAgainstNull) != 0) {
+ if (types.Contains(CompareNilICStub::NULL_TYPE)) {
if (needs_or) if_nil.Or();
if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
needs_or = true;
}
- if ((types & CompareNilICStub::kCompareAgainstUndefined) != 0) {
+ if (types.Contains(CompareNilICStub::UNDEFINED)) {
if (needs_or) if_nil.Or();
if_nil.If<HCompareObjectEqAndBranch>(value,
graph()->GetConstantUndefined());
needs_or = true;
}
// Handle either undetectable or monomorphic, not both.
- ASSERT(((types & CompareNilICStub::kCompareAgainstUndetectable) == 0) ||
- ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) == 0));
- if ((types & CompareNilICStub::kCompareAgainstUndetectable) != 0) {
+ ASSERT(!types.Contains(CompareNilICStub::UNDETECTABLE) ||
+ !types.Contains(CompareNilICStub::MONOMORPHIC_MAP));
+ if (types.Contains(CompareNilICStub::UNDETECTABLE)) {
if (needs_or) if_nil.Or();
if_nil.If<HIsUndetectableAndBranch>(value);
} else {
if_nil.Then();
if_nil.Else();
- if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
+ if (types.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
BuildCheckNonSmi(value);
// For ICs, the map checked below is a sentinel map that gets replaced by
// the monomorphic map when the code is used as a template to generate a
@@ -2615,50 +2614,6 @@
}
-void HGraph::EliminateUnreachablePhis() {
- HPhase phase("H_Unreachable phi elimination", this);
-
- // Initialize worklist.
- ZoneList<HPhi*> phi_list(blocks_.length(), zone());
- ZoneList<HPhi*> worklist(blocks_.length(), zone());
- for (int i = 0; i < blocks_.length(); ++i) {
- for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
- HPhi* phi = blocks_[i]->phis()->at(j);
- phi_list.Add(phi, zone());
- // We can't eliminate phis in the receiver position in the environment
- // because in case of throwing an error we need this value to
- // construct a stack trace.
- if (phi->HasRealUses() || phi->IsReceiver()) {
- phi->set_is_live(true);
- worklist.Add(phi, zone());
- }
- }
- }
-
- // Iteratively mark live phis.
- while (!worklist.is_empty()) {
- HPhi* phi = worklist.RemoveLast();
- for (int i = 0; i < phi->OperandCount(); i++) {
- HValue* operand = phi->OperandAt(i);
- if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
- HPhi::cast(operand)->set_is_live(true);
- worklist.Add(HPhi::cast(operand), zone());
- }
- }
- }
-
- // Remove unreachable phis.
- for (int i = 0; i < phi_list.length(); i++) {
- HPhi* phi = phi_list[i];
- if (!phi->is_live()) {
- HBasicBlock* block = phi->block();
- block->RemovePhi(phi);
- block->RecordDeletedPhi(phi->merged_index());
- }
- }
-}
-
-
bool HGraph::CheckArgumentsPhiUses() {
int block_count = blocks_.length();
for (int i = 0; i < block_count; ++i) {
@@ -4919,7 +4874,11 @@
"Unsupported phi use of arguments"));
return false;
}
- if (FLAG_eliminate_dead_phis) EliminateUnreachablePhis();
+
+ // Remove dead code and phis
+ if (FLAG_dead_code_elimination) {
+ DeadCodeElimination("H_Eliminate early dead code");
+ }
CollectPhis();
if (has_osr_loop_entry()) {
@@ -4967,7 +4926,9 @@
EliminateRedundantBoundsChecks();
}
if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations();
- if (FLAG_dead_code_elimination) DeadCodeElimination();
+ if (FLAG_dead_code_elimination) {
+ DeadCodeElimination("H_Eliminate late dead code");
+ }
RestoreActualValues();
@@ -5444,35 +5405,98 @@
}
-void HGraph::DeadCodeElimination() {
- HPhase phase("H_Dead code elimination", this);
- ZoneList<HInstruction*> worklist(blocks_.length(), zone());
+void HGraph::DeadCodeElimination(const char* phase_name) {
+ HPhase phase(phase_name, this);
+ MarkLiveInstructions();
+ RemoveDeadInstructions();
+}
+
+
+void HGraph::MarkLiveInstructions() {
+ ZoneList<HValue*> worklist(blocks_.length(), zone());
+
+ // Mark initial root instructions for dead code elimination.
for (int i = 0; i < blocks()->length(); ++i) {
- for (HInstruction* instr = blocks()->at(i)->first();
+ HBasicBlock* block = blocks()->at(i);
+ for (HInstruction* instr = block->first();
instr != NULL;
instr = instr->next()) {
- if (instr->IsDead()) worklist.Add(instr, zone());
+ if (instr->CannotBeEliminated()) MarkLive(NULL, instr, &worklist);
+ }
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ if (phi->CannotBeEliminated()) MarkLive(NULL, phi, &worklist);
}
}
+ // Transitively mark all inputs of live instructions live.
while (!worklist.is_empty()) {
- HInstruction* instr = worklist.RemoveLast();
- // This happens when an instruction is used multiple times as operand. That
- // in turn could happen through GVN.
- if (!instr->IsLinked()) continue;
+ HValue* instr = worklist.RemoveLast();
+ for (int i = 0; i < instr->OperandCount(); ++i) {
+ MarkLive(instr, instr->OperandAt(i), &worklist);
+ }
+ }
+}
+
+
+void HGraph::MarkLive(HValue* ref, HValue* instr, ZoneList<HValue*>* worklist) {
+ if (!instr->CheckFlag(HValue::kIsLive)) {
+ instr->SetFlag(HValue::kIsLive);
+ worklist->Add(instr, zone());
+
if (FLAG_trace_dead_code_elimination) {
HeapStringAllocator allocator;
StringStream stream(&allocator);
- instr->PrintNameTo(&stream);
- stream.Add(" = ");
+ ALLOW_HANDLE_DEREF(isolate(), "debug mode printing");
+ if (ref != NULL) {
+ ref->PrintTo(&stream);
+ } else {
+ stream.Add("root ");
+ }
+ stream.Add(" -> ");
instr->PrintTo(&stream);
- PrintF("[removing dead instruction %s]\n", *stream.ToCString());
+ PrintF("[MarkLive %s]\n", *stream.ToCString());
}
- instr->DeleteAndReplaceWith(NULL);
- for (int i = 0; i < instr->OperandCount(); ++i) {
- HValue* operand = instr->OperandAt(i);
- if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone());
+ }
+}
+
+
+void HGraph::RemoveDeadInstructions() {
+ ZoneList<HPhi*> dead_phis(blocks_.length(), zone());
+
+ // Remove any instruction not marked kIsLive.
+ for (int i = 0; i < blocks()->length(); ++i) {
+ HBasicBlock* block = blocks()->at(i);
+ for (HInstruction* instr = block->first();
+ instr != NULL;
+ instr = instr->next()) {
+ if (!instr->CheckFlag(HValue::kIsLive)) {
+ // Instruction has not been marked live; assume it is dead and remove.
+ // TODO(titzer): we don't remove constants because some special ones
+ // might be used by later phases and are assumed to be in the graph
+ if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
+ } else {
+ // Clear the liveness flag to leave the graph clean for the next DCE.
+ instr->ClearFlag(HValue::kIsLive);
+ }
}
+ // Collect phis that are dead and remove them in the next pass.
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ if (!phi->CheckFlag(HValue::kIsLive)) {
+ dead_phis.Add(phi, zone());
+ } else {
+ phi->ClearFlag(HValue::kIsLive);
+ }
+ }
+ }
+
+ // Process phis separately to avoid simultaneously mutating the phi list.
+ while (!dead_phis.is_empty()) {
+ HPhi* phi = dead_phis.RemoveLast();
+ HBasicBlock* block = phi->block();
+ phi->DeleteAndReplaceWith(NULL);
+ block->RecordDeletedPhi(phi->merged_index());
}
}
@@ -10305,7 +10329,7 @@
}
-bool CanBeZero(HValue *right) {
+bool CanBeZero(HValue* right) {
if (right->IsConstant()) {
HConstant* right_const = HConstant::cast(right);
if (right_const->HasInteger32Value() &&
@@ -10799,15 +10823,13 @@
TypeFeedbackId id = expr->CompareOperationFeedbackId();
CompareNilICStub::Types types;
if (kind == kStrictEquality) {
- if (nil == kNullValue) {
- types = CompareNilICStub::kCompareAgainstNull;
- } else {
- types = CompareNilICStub::kCompareAgainstUndefined;
- }
+ types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
+ CompareNilICStub::UNDEFINED);
} else {
- types = static_cast<CompareNilICStub::Types>(
- oracle()->CompareNilTypes(id));
- if (types == 0) types = CompareNilICStub::kFullCompare;
+ types = CompareNilICStub::Types(oracle()->CompareNilTypes(id));
+ if (types.IsEmpty()) {
+ types = CompareNilICStub::Types::FullCompare();
+ }
}
Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
BuildCompareNil(value, kind, types, map_handle,
@@ -10912,9 +10934,11 @@
boilerplate_object->map()->instance_descriptors());
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
+ int copied_fields = 0;
for (int i = 0; i < limit; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (details.type() != FIELD) continue;
+ copied_fields++;
int index = descriptors->GetFieldIndex(i);
int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
Handle<Name> name(descriptors->GetKey(i));
@@ -10953,6 +10977,16 @@
}
}
+ int inobject_properties = boilerplate_object->map()->inobject_properties();
+ HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
+ factory->one_pointer_filler_map(), Representation::Tagged()));
+ for (int i = copied_fields; i < inobject_properties; i++) {
+ AddInstruction(new(zone) HStoreNamedField(
+ object_properties, factory->unknown_field_string(), value_instruction,
+ true, Representation::Tagged(),
+ boilerplate_object->GetInObjectPropertyOffset(i)));
+ }
+
// Build Allocation Site Info if desired
if (create_allocation_site_info) {
BuildCreateAllocationSiteInfo(target, JSArray::kSize, original_boilerplate);
diff --git a/src/hydrogen.h b/src/hydrogen.h
index a0d9bbc..b053fc7 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -277,17 +277,15 @@
void GlobalValueNumbering();
bool ProcessArgumentsObject();
void EliminateRedundantPhis();
- void EliminateUnreachablePhis();
void Canonicalize();
void OrderBlocks();
void AssignDominators();
void SetupInformativeDefinitions();
void EliminateRedundantBoundsChecks();
void DehoistSimpleArrayIndexComputations();
- void DeadCodeElimination();
void RestoreActualValues();
+ void DeadCodeElimination(const char *phase_name);
void PropagateDeoptimizingMark();
- void EliminateUnusedInstructions();
// Returns false if there are phi-uses of the arguments-object
// which are not supported by the optimizing compiler.
@@ -410,6 +408,9 @@
HConstant* GetConstantSmi(SetOncePointer<HConstant>* pointer,
int32_t integer_value);
+ void MarkLive(HValue* ref, HValue* instr, ZoneList<HValue*>* worklist);
+ void MarkLiveInstructions();
+ void RemoveDeadInstructions();
void MarkAsDeoptimizingRecursively(HBasicBlock* block);
void NullifyUnreachableInstructions();
void InsertTypeConversions(HInstruction* instr);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 29569fa..507aeb6 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -292,8 +292,8 @@
// Map must never be empty, so check the first elements.
Label install_optimized;
// Speculatively move code object into edx.
- __ mov(edx, FieldOperand(ebx, FixedArray::kHeaderSize + kPointerSize));
- __ cmp(ecx, FieldOperand(ebx, FixedArray::kHeaderSize));
+ __ mov(edx, FieldOperand(ebx, SharedFunctionInfo::kFirstCodeSlot));
+ __ cmp(ecx, FieldOperand(ebx, SharedFunctionInfo::kFirstContextSlot));
__ j(equal, &install_optimized);
// Iterate through the rest of map backwards. edx holds an index as a Smi.
@@ -302,10 +302,9 @@
__ mov(edx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ bind(&loop);
// Do not double check first entry.
- __ cmp(edx, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
+ __ cmp(edx, Immediate(Smi::FromInt(SharedFunctionInfo::kSecondEntryIndex)));
__ j(equal, &restore);
- __ sub(edx, Immediate(Smi::FromInt(
- SharedFunctionInfo::kEntryLength))); // Skip an entry.
+ __ sub(edx, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
__ cmp(ecx, CodeGenerator::FixedArrayElementOperand(ebx, edx, 0));
__ j(not_equal, &loop, Label::kNear);
// Hit: fetch the optimized code.
@@ -1227,6 +1226,14 @@
}
+static void BinaryOpStub_GenerateRegisterArgsPop(MacroAssembler* masm) {
+ __ pop(ecx);
+ __ pop(eax);
+ __ pop(edx);
+ __ push(ecx);
+}
+
+
static void BinaryOpStub_GenerateSmiCode(
MacroAssembler* masm,
Label* slow,
@@ -1662,7 +1669,6 @@
case Token::SUB:
case Token::MUL:
case Token::DIV:
- GenerateRegisterArgsPush(masm);
break;
case Token::MOD:
case Token::BIT_OR:
@@ -1671,11 +1677,19 @@
case Token::SAR:
case Token::SHL:
case Token::SHR:
+ BinaryOpStub_GenerateRegisterArgsPop(masm);
break;
default:
UNREACHABLE();
}
- GenerateCallRuntime(masm);
+
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ push(edx);
+ __ push(eax);
+ GenerateCallRuntime(masm);
+ }
+ __ ret(0);
}
@@ -1700,7 +1714,8 @@
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
__ j(above_equal, &call_runtime, Label::kNear);
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
+ StringAddStub string_add_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_stub);
@@ -1892,7 +1907,6 @@
case Token::SUB:
case Token::MUL:
case Token::DIV:
- GenerateRegisterArgsPush(masm);
break;
case Token::MOD:
return; // Handled above.
@@ -1902,11 +1916,19 @@
case Token::SAR:
case Token::SHL:
case Token::SHR:
+ BinaryOpStub_GenerateRegisterArgsPop(masm);
break;
default:
UNREACHABLE();
}
- GenerateCallRuntime(masm);
+
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ push(edx);
+ __ push(eax);
+ GenerateCallRuntime(masm);
+ }
+ __ ret(0);
}
@@ -2109,7 +2131,6 @@
case Token::MUL:
case Token::DIV:
case Token::MOD:
- GenerateRegisterArgsPush(masm);
break;
case Token::BIT_OR:
case Token::BIT_AND:
@@ -2117,11 +2138,19 @@
case Token::SAR:
case Token::SHL:
case Token::SHR:
+ BinaryOpStub_GenerateRegisterArgsPop(masm);
break;
default:
UNREACHABLE();
}
- GenerateCallRuntime(masm);
+
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ push(edx);
+ __ push(eax);
+ GenerateCallRuntime(masm);
+ }
+ __ ret(0);
}
@@ -2287,7 +2316,6 @@
case Token::SUB:
case Token::MUL:
case Token::DIV:
- GenerateRegisterArgsPush(masm);
break;
case Token::MOD:
case Token::BIT_OR:
@@ -2296,11 +2324,19 @@
case Token::SAR:
case Token::SHL:
case Token::SHR:
+ BinaryOpStub_GenerateRegisterArgsPop(masm);
break;
default:
UNREACHABLE();
}
- GenerateCallRuntime(masm);
+
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ push(edx);
+ __ push(eax);
+ GenerateCallRuntime(masm);
+ }
+ __ ret(0);
}
@@ -2317,7 +2353,8 @@
__ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
__ j(above_equal, &left_not_string, Label::kNear);
- StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
+ StringAddStub string_add_left_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_left_stub);
@@ -2327,7 +2364,8 @@
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
__ j(above_equal, &call_runtime, Label::kNear);
- StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
+ StringAddStub string_add_right_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_right_stub);
@@ -5737,7 +5775,7 @@
__ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
// Make sure that both arguments are strings if not known in advance.
- if (flags_ == NO_STRING_ADD_FLAGS) {
+ if ((flags_ & NO_STRING_ADD_FLAGS) != 0) {
__ JumpIfSmi(eax, &call_runtime);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
__ j(above_equal, &call_runtime);
@@ -6045,15 +6083,52 @@
__ Drop(2);
// Just jump to runtime to add the two strings.
__ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm, ecx);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ CallRuntime(Runtime::kStringAdd, 2);
+ }
+ __ ret(0);
+ } else {
+ __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ }
if (call_builtin.is_linked()) {
__ bind(&call_builtin);
- __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm, ecx);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(builtin_id, CALL_FUNCTION);
+ }
+ __ ret(0);
+ } else {
+ __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ }
}
}
+void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+ __ push(eax);
+ __ push(edx);
+}
+
+
+void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm,
+ Register temp) {
+ __ pop(temp);
+ __ pop(edx);
+ __ pop(eax);
+ __ push(temp);
+}
+
+
void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
int stack_offset,
Register arg,
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index fbf1a68..6dc63bd 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -218,13 +218,14 @@
};
-// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
- NO_STRING_ADD_FLAGS = 0,
+ NO_STRING_ADD_FLAGS = 1 << 0,
// Omit left string check in stub (left is definitely a string).
- NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
+ NO_STRING_CHECK_LEFT_IN_STUB = 1 << 1,
// Omit right string check in stub (right is definitely a string).
- NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
+ NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 2,
+ // Stub needs a frame before calling the runtime
+ ERECT_FRAME = 1 << 3,
// Omit both string checks in stub.
NO_STRING_CHECK_IN_STUB =
NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
@@ -249,6 +250,9 @@
Register scratch3,
Label* slow);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
+
const StringAddFlags flags_;
};
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 21c7ff5..9f3c4e9 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -362,7 +362,7 @@
if (FLAG_trace_osr) {
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => node=%u, frame=%d->%d, ebp:esp=0x%08x:0x%08x]\n",
ast_id,
input_frame_size,
@@ -476,203 +476,12 @@
PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
ok ? "finished" : "aborted",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
}
}
-void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
- int frame_index) {
- BailoutId node_id = BailoutId(iterator->Next());
- JSFunction* function;
- if (frame_index != 0) {
- function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- } else {
- int closure_id = iterator->Next();
- USE(closure_id);
- ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
- function = function_;
- }
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating ");
- function->PrintName();
- PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
- }
-
- // The 'fixed' part of the frame consists of the incoming parameters and
- // the part described by JavaScriptFrameConstants.
- unsigned fixed_frame_size = ComputeFixedSize(function);
- unsigned input_frame_size = input_->GetFrameSize();
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
-
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
- ASSERT(frame_index >= 0 && frame_index < output_count_);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // Compute the incoming parameter translation.
- int parameter_count = function->shared()->formal_parameter_count() + 1;
- unsigned output_offset = output_frame_size;
- unsigned input_offset = input_frame_size;
-
- unsigned alignment_state_offset =
- input_offset - parameter_count * kPointerSize -
- StandardFrameConstants::kFixedFrameSize -
- kPointerSize;
- ASSERT(JavaScriptFrameConstants::kDynamicAlignmentStateOffset ==
- JavaScriptFrameConstants::kLocal0Offset);
-
- // The top address for the bottommost output frame can be computed from
- // the input frame pointer and the output frame's height. For all
- // subsequent output frames, it can be computed from the previous one's
- // top address and the current frame's size.
- uint32_t top_address;
- if (is_bottommost) {
- int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset);
- has_alignment_padding_ =
- (alignment_state == kAlignmentPaddingPushed) ? 1 : 0;
- // 2 = context and function in the frame.
- // If the optimized frame had alignment padding, adjust the frame pointer
- // to point to the new position of the old frame pointer after padding
- // is removed. Subtract 2 * kPointerSize for the context and function slots.
- top_address = input_->GetRegister(ebp.code()) - (2 * kPointerSize) -
- height_in_bytes + has_alignment_padding_ * kPointerSize;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
- output_frame->SetTop(top_address);
-
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- input_offset -= (parameter_count * kPointerSize);
-
- // There are no translation commands for the caller's pc and fp, the
- // context, and the function. Synthesize their values and set them up
- // explicitly.
- //
- // The caller's pc for the bottommost output frame is the same as in the
- // input frame. For all subsequent output frames, it can be read from the
- // previous one. This frame's pc can be computed from the non-optimized
- // function code and AST id of the bailout.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- intptr_t value;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetPc();
- }
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The caller's frame pointer for the bottommost output frame is the same
- // as in the input frame. For all subsequent output frames, it can be
- // read from the previous one. Also compute and set this frame's frame
- // pointer.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetFp();
- }
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- ASSERT(!is_bottommost ||
- (input_->GetRegister(ebp.code()) + has_alignment_padding_ * kPointerSize) ==
- fp_value);
- output_frame->SetFp(fp_value);
- if (is_topmost) output_frame->SetRegister(ebp.code(), fp_value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
- ASSERT(!is_bottommost || !has_alignment_padding_ ||
- (fp_value & kPointerSize) != 0);
-
- // For the bottommost output frame the context can be gotten from the input
- // frame. For all subsequent output frames it can be gotten from the function
- // so long as we don't inline functions that need local contexts.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = reinterpret_cast<uint32_t>(function->context());
- }
- output_frame->SetFrameSlot(output_offset, value);
- output_frame->SetContext(value);
- if (is_topmost) output_frame->SetRegister(esi.code(), value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The function was mentioned explicitly in the BEGIN_FRAME.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(function);
- // The function for the bottommost output frame should also agree with the
- // input frame.
- ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Translate the rest of the frame.
- for (unsigned i = 0; i < height; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- ASSERT(0 == output_offset);
-
- // Compute this frame's PC, state, and continuation.
- Code* non_optimized_code = function->shared()->code();
- FixedArray* raw_data = non_optimized_code->deoptimization_data();
- DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
- Address start = non_optimized_code->instruction_start();
- unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
- unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
- uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
- output_frame->SetPc(pc_value);
-
- FullCodeGenerator::State state =
- FullCodeGenerator::StateField::decode(pc_and_state);
- output_frame->SetState(Smi::FromInt(state));
-
- // Set the continuation for the topmost frame.
- if (is_topmost && bailout_type_ != DEBUGGER) {
- Builtins* builtins = isolate_->builtins();
- Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
- if (bailout_type_ == LAZY) {
- continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
- } else if (bailout_type_ == SOFT) {
- continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
- } else {
- ASSERT(bailout_type_ == EAGER);
- }
- output_frame->SetContinuation(
- reinterpret_cast<uint32_t>(continuation->entry()));
- }
-}
-
-
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
@@ -715,6 +524,20 @@
}
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+ int parameter_count = function->shared()->formal_parameter_count() + 1;
+ unsigned input_frame_size = input_->GetFrameSize();
+ unsigned alignment_state_offset =
+ input_frame_size - parameter_count * kPointerSize -
+ StandardFrameConstants::kFixedFrameSize -
+ kPointerSize;
+ ASSERT(JavaScriptFrameConstants::kDynamicAlignmentStateOffset ==
+ JavaScriptFrameConstants::kLocal0Offset);
+ int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset);
+ return (alignment_state == kAlignmentPaddingPushed);
+}
+
+
#define __ masm()->
void Deoptimizer::EntryGenerator::Generate() {
diff --git a/src/ia32/frames-ia32.cc b/src/ia32/frames-ia32.cc
index 4932fa3..ea19e9f 100644
--- a/src/ia32/frames-ia32.cc
+++ b/src/ia32/frames-ia32.cc
@@ -43,6 +43,10 @@
}
+Register JavaScriptFrame::fp_register() { return ebp; }
+Register JavaScriptFrame::context_register() { return esi; }
+
+
Register StubFailureTrampolineFrame::fp_register() { return ebp; }
Register StubFailureTrampolineFrame::context_register() { return esi; }
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 5a78019..1bc72ec 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -161,6 +161,7 @@
__ mov(ebp, esp);
__ push(esi); // Callee's context.
__ push(edi); // Callee's JS Function.
+ info->AddNoFrameRange(0, masm_->pc_offset());
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
@@ -410,6 +411,7 @@
// Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger.
__ mov(esp, ebp);
+ int no_frame_start = masm_->pc_offset();
__ pop(ebp);
int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
@@ -420,6 +422,7 @@
ASSERT(Assembler::kJSReturnSequenceLength <=
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
}
}
@@ -1922,8 +1925,95 @@
break;
}
- case Yield::DELEGATING:
- UNIMPLEMENTED();
+ case Yield::DELEGATING: {
+ VisitForStackValue(expr->generator_object());
+
+ // Initial stack layout is as follows:
+ // [sp + 1 * kPointerSize] iter
+ // [sp + 0 * kPointerSize] g
+
+ Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+ // Initial send value is undefined.
+ __ mov(eax, isolate()->factory()->undefined_value());
+ __ jmp(&l_send);
+
+ // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
+ __ bind(&l_catch);
+ handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+ __ mov(edx, Operand(esp, 1 * kPointerSize)); // iter
+ __ push(edx); // iter
+ __ push(eax); // exception
+ __ mov(ecx, isolate()->factory()->throw_string()); // "throw"
+ Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(throw_ic); // iter.throw in eax
+ __ jmp(&l_call);
+
+ // try { received = yield result.value }
+ __ bind(&l_try);
+ __ pop(eax); // result.value
+ __ PushTryHandler(StackHandler::CATCH, expr->index());
+ const int handler_size = StackHandlerConstants::kSize;
+ __ push(eax); // result.value
+ __ push(Operand(esp, (0 + 1) * kPointerSize + handler_size)); // g
+ __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+ __ mov(context_register(),
+ Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ CompareRoot(eax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &l_resume);
+ EmitReturnIteratorResult(false);
+ __ bind(&l_resume); // received in eax
+ __ PopTryHandler();
+
+ // receiver = iter; f = iter.send; arg = received;
+ __ bind(&l_send);
+ __ mov(edx, Operand(esp, 1 * kPointerSize)); // iter
+ __ push(edx); // iter
+ __ push(eax); // received
+ __ mov(ecx, isolate()->factory()->send_string()); // "send"
+ Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(send_ic); // iter.send in eax
+
+ // result = f.call(receiver, arg);
+ __ bind(&l_call);
+ Label l_call_runtime;
+ __ JumpIfSmi(eax, &l_call_runtime);
+ __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
+ __ j(not_equal, &l_call_runtime);
+ __ mov(edi, eax);
+ ParameterCount count(1);
+ __ InvokeFunction(edi, count, CALL_FUNCTION,
+ NullCallWrapper(), CALL_AS_METHOD);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ jmp(&l_loop);
+ __ bind(&l_call_runtime);
+ __ push(eax);
+ __ CallRuntime(Runtime::kCall, 3);
+
+ // val = result.value; if (!result.done) goto l_try;
+ __ bind(&l_loop);
+ // result.value
+ __ push(eax); // save result
+ __ mov(edx, eax); // result
+ __ mov(ecx, isolate()->factory()->value_string()); // "value"
+ Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(value_ic); // result.value in eax
+ __ pop(ebx); // result
+ __ push(eax); // result.value
+ __ mov(edx, ebx); // result
+ __ mov(ecx, isolate()->factory()->done_string()); // "done"
+ Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(done_ic); // result.done in eax
+ ToBooleanStub stub(eax);
+ __ push(eax);
+ __ CallStub(&stub);
+ __ test(eax, eax);
+ __ j(zero, &l_try);
+
+ // result.value
+ __ pop(eax); // result.value
+ context()->DropAndPlug(2, eax); // drop iter and g
+ break;
+ }
}
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 7089c76..b6244af 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -210,6 +210,7 @@
frame_is_built_ = true;
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
+ info()->AddNoFrameRange(0, masm_->pc_offset());
__ push(esi); // Callee's context.
if (info()->IsStub()) {
__ push(Immediate(Smi::FromInt(StackFrame::STUB)));
@@ -2317,46 +2318,6 @@
}
-void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
- Register reg = ToRegister(instr->value());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- // If the expression is known to be untagged or a smi, then it's definitely
- // not null, and it can't be a an undetectable object.
- if (instr->hydrogen()->representation().IsSpecialization() ||
- instr->hydrogen()->type().IsSmi()) {
- EmitGoto(false_block);
- return;
- }
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- Handle<Object> nil_value = instr->nil() == kNullValue ?
- factory()->null_value() :
- factory()->undefined_value();
- __ cmp(reg, nil_value);
- if (instr->kind() == kStrictEquality) {
- EmitBranch(true_block, false_block, equal);
- } else {
- Handle<Object> other_nil_value = instr->nil() == kNullValue ?
- factory()->undefined_value() :
- factory()->null_value();
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ j(equal, true_label);
- __ cmp(reg, other_nil_value);
- __ j(equal, true_label);
- __ JumpIfSmi(reg, false_label);
- // Check for undetectable objects by looking in the bit field in
- // the map. The object has already been smi checked.
- Register scratch = ToRegister(instr->temp());
- __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
- __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
- __ test(scratch, Immediate(1 << Map::kIsUndetectable));
- EmitBranch(true_block, false_block, not_zero);
- }
-}
-
-
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Label* is_not_object,
@@ -2846,9 +2807,11 @@
__ mov(edx, Operand(ebp,
JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
}
+ int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ mov(esp, ebp);
__ pop(ebp);
+ no_frame_start = masm_->pc_offset();
}
if (dynamic_frame_alignment_) {
Label no_padding;
@@ -2860,6 +2823,9 @@
}
EmitReturn(instr, false);
+ if (no_frame_start != -1) {
+ info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+ }
}
@@ -3359,7 +3325,8 @@
uint32_t offset,
uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
- int shift_size = ElementsKindToShiftSize(elements_kind);
+ int element_shift_size = ElementsKindToShiftSize(elements_kind);
+ int shift_size = element_shift_size;
if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) {
@@ -3377,7 +3344,7 @@
return Operand(elements_pointer_reg,
ToRegister(key),
scale_factor,
- offset + (additional_index << shift_size));
+ offset + (additional_index << element_shift_size));
}
}
@@ -3533,6 +3500,11 @@
}
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
+ __ int3();
+}
+
+
void LCodeGen::DoPushArgument(LPushArgument* instr) {
LOperand* argument = instr->value();
EmitPushTaggedOperand(argument);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 1d41505..dec5697 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -235,15 +235,6 @@
}
-void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if ");
- value()->PrintTo(stream);
- stream->Add(kind() == kStrictEquality ? " === " : " == ");
- stream->Add(nil() == kNullValue ? "null" : "undefined");
- stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
value()->PrintTo(stream);
@@ -1058,6 +1049,11 @@
}
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+ return new(zone()) LDebugBreak();
+}
+
+
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
@@ -1733,13 +1729,6 @@
}
-LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
- // We only need a temp register for non-strict compare.
- LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
- return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
-}
-
-
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* temp = TempRegister();
@@ -1856,6 +1845,7 @@
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegister(instr->index());
ASSERT(ecx.is_byte_register());
+ // TODO(titzer): the machine code for this instruction overwrites ecx! fix!
LOperand* value = UseFixed(instr->value(), ecx);
LSeqStringSetChar* result =
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 29f8a8a..b32ead9 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -84,6 +84,7 @@
V(ConstantI) \
V(ConstantT) \
V(Context) \
+ V(DebugBreak) \
V(DeclareGlobals) \
V(DeleteProperty) \
V(Deoptimize) \
@@ -108,7 +109,6 @@
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
- V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
@@ -570,6 +570,12 @@
};
+class LDebugBreak: public LTemplateInstruction<0, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
class LModI: public LTemplateInstruction<1, 2, 1> {
public:
LModI(LOperand* left, LOperand* right, LOperand* temp) {
@@ -832,26 +838,6 @@
};
-class LIsNilAndBranch: public LControlInstruction<1, 1> {
- public:
- LIsNilAndBranch(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- LOperand* value() { return inputs_[0]; }
- LOperand* temp() { return temps_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
-
- EqualityKind kind() const { return hydrogen()->kind(); }
- NilValue nil() const { return hydrogen()->nil(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsObjectAndBranch: public LControlInstruction<1, 1> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/ic.cc b/src/ic.cc
index 75c22c4..ea0c1fb 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2888,25 +2888,17 @@
}
-Code* CompareNilIC::GetRawUninitialized(EqualityKind kind,
- NilValue nil) {
- CompareNilICStub stub(kind, nil);
- Code* code = NULL;
- CHECK(stub.FindCodeInCache(&code, Isolate::Current()));
- return code;
-}
-
-
void CompareNilIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
Code::ExtraICState state = target->extended_extra_ic_state();
- EqualityKind kind =
- CompareNilICStub::EqualityKindFromExtraICState(state);
- NilValue nil =
- CompareNilICStub::NilValueFromExtraICState(state);
+ CompareNilICStub stub(state, CompareNilICStub::CODE_STUB_IS_MISS);
+ stub.ClearTypes();
- SetTargetAtAddress(address, GetRawUninitialized(kind, nil));
+ Code* code = NULL;
+ CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
+
+ SetTargetAtAddress(address, code);
}
@@ -2930,28 +2922,24 @@
MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
+ CompareNilICStub stub(extra_ic_state);
+
// Extract the current supported types from the patched IC and calculate what
// types must be supported as a result of the miss.
- bool already_monomorphic;
- CompareNilICStub::Types types =
- CompareNilICStub::GetPatchedICFlags(extra_ic_state,
- object, &already_monomorphic);
+ bool already_monomorphic = stub.IsMonomorphic();
- EqualityKind kind =
- CompareNilICStub::EqualityKindFromExtraICState(extra_ic_state);
- NilValue nil =
- CompareNilICStub::NilValueFromExtraICState(extra_ic_state);
+ stub.Record(object);
+
+ EqualityKind kind = stub.GetKind();
+ NilValue nil = stub.GetNilValue();
// Find or create the specialized stub to support the new set of types.
- CompareNilICStub stub(kind, nil, types);
Handle<Code> code;
- if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
+ if (stub.IsMonomorphic()) {
Handle<Map> monomorphic_map(already_monomorphic
? target()->FindFirstMap()
: HeapObject::cast(*object)->map());
- code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map,
- nil,
- stub.GetTypes());
+ code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
} else {
code = stub.GetCode(isolate());
}
diff --git a/src/ic.h b/src/ic.h
index 739f34c..a044f0c 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -787,8 +787,6 @@
static Handle<Code> GetUninitialized();
- static Code* GetRawUninitialized(EqualityKind kind, NilValue nil);
-
static void Clear(Address address, Code* target);
void patch(Code* code);
diff --git a/src/log.cc b/src/log.cc
index e52d0f3..00fa432 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -1016,6 +1016,7 @@
void Logger::CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
Name* name) {
if (!is_logging_code_events()) return;
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
@@ -1093,6 +1094,7 @@
void Logger::CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
Name* source, int line) {
if (!is_logging_code_events()) return;
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
@@ -1735,20 +1737,20 @@
PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code, *shared,
+ *code, *shared, NULL,
*script_name, line_num + 1));
} else {
// Can't distinguish eval and script here, so always use Script.
PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *code, *shared, *script_name));
+ *code, *shared, NULL, *script_name));
}
} else {
PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code, *shared, *func_name));
+ *code, *shared, NULL, *func_name));
}
} else if (shared->IsApiFunction()) {
// API function.
@@ -1763,7 +1765,7 @@
} else {
PROFILE(isolate_,
CodeCreateEvent(
- Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
+ Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
}
}
diff --git a/src/log.h b/src/log.h
index 8db13df..531f1de 100644
--- a/src/log.h
+++ b/src/log.h
@@ -79,6 +79,7 @@
class Isolate;
class PositionsRecorder;
class CpuProfiler;
+class CompilationInfo;
#undef LOG
#define LOG(isolate, Call) \
@@ -235,10 +236,12 @@
void CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
Name* name);
void CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
+ CompilationInfo* info,
Name* source, int line);
void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
void CodeMovingGCEvent();
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 62dee48..29d8616 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1054,6 +1054,70 @@
}
+void CodeFlusher::ProcessOptimizedCodeMaps() {
+ static const int kEntriesStart = SharedFunctionInfo::kEntriesStart;
+ static const int kEntryLength = SharedFunctionInfo::kEntryLength;
+ static const int kContextOffset = 0;
+ static const int kCodeOffset = 1;
+ static const int kLiteralsOffset = 2;
+ STATIC_ASSERT(kEntryLength == 3);
+
+ SharedFunctionInfo* holder = optimized_code_map_holder_head_;
+ SharedFunctionInfo* next_holder;
+ while (holder != NULL) {
+ next_holder = GetNextCodeMap(holder);
+ ClearNextCodeMap(holder);
+
+ FixedArray* code_map = FixedArray::cast(holder->optimized_code_map());
+ int new_length = kEntriesStart;
+ int old_length = code_map->length();
+ for (int i = kEntriesStart; i < old_length; i += kEntryLength) {
+ Code* code = Code::cast(code_map->get(i + kCodeOffset));
+ MarkBit code_mark = Marking::MarkBitFrom(code);
+ if (!code_mark.Get()) {
+ continue;
+ }
+
+ // Update and record the context slot in the optimizled code map.
+ Object** context_slot = HeapObject::RawField(code_map,
+ FixedArray::OffsetOfElementAt(new_length));
+ code_map->set(new_length++, code_map->get(i + kContextOffset));
+ ASSERT(Marking::IsBlack(
+ Marking::MarkBitFrom(HeapObject::cast(*context_slot))));
+ isolate_->heap()->mark_compact_collector()->
+ RecordSlot(context_slot, context_slot, *context_slot);
+
+ // Update and record the code slot in the optimized code map.
+ Object** code_slot = HeapObject::RawField(code_map,
+ FixedArray::OffsetOfElementAt(new_length));
+ code_map->set(new_length++, code_map->get(i + kCodeOffset));
+ ASSERT(Marking::IsBlack(
+ Marking::MarkBitFrom(HeapObject::cast(*code_slot))));
+ isolate_->heap()->mark_compact_collector()->
+ RecordSlot(code_slot, code_slot, *code_slot);
+
+ // Update and record the literals slot in the optimized code map.
+ Object** literals_slot = HeapObject::RawField(code_map,
+ FixedArray::OffsetOfElementAt(new_length));
+ code_map->set(new_length++, code_map->get(i + kLiteralsOffset));
+ ASSERT(Marking::IsBlack(
+ Marking::MarkBitFrom(HeapObject::cast(*literals_slot))));
+ isolate_->heap()->mark_compact_collector()->
+ RecordSlot(literals_slot, literals_slot, *literals_slot);
+ }
+
+ // Trim the optimized code map if entries have been removed.
+ if (new_length < old_length) {
+ holder->TrimOptimizedCodeMap(old_length - new_length);
+ }
+
+ holder = next_holder;
+ }
+
+ optimized_code_map_holder_head_ = NULL;
+}
+
+
void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) {
// Make sure previous flushing decisions are revisited.
isolate_->heap()->incremental_marking()->RecordWrites(shared_info);
@@ -1112,6 +1176,36 @@
}
+void CodeFlusher::EvictOptimizedCodeMap(SharedFunctionInfo* code_map_holder) {
+ ASSERT(!FixedArray::cast(code_map_holder->optimized_code_map())->
+ get(SharedFunctionInfo::kNextMapIndex)->IsUndefined());
+
+ // Make sure previous flushing decisions are revisited.
+ isolate_->heap()->incremental_marking()->RecordWrites(code_map_holder);
+
+ SharedFunctionInfo* holder = optimized_code_map_holder_head_;
+ SharedFunctionInfo* next_holder;
+ if (holder == code_map_holder) {
+ next_holder = GetNextCodeMap(code_map_holder);
+ optimized_code_map_holder_head_ = next_holder;
+ ClearNextCodeMap(code_map_holder);
+ } else {
+ while (holder != NULL) {
+ next_holder = GetNextCodeMap(holder);
+
+ if (next_holder == code_map_holder) {
+ next_holder = GetNextCodeMap(code_map_holder);
+ SetNextCodeMap(holder, next_holder);
+ ClearNextCodeMap(code_map_holder);
+ break;
+ }
+
+ holder = next_holder;
+ }
+ }
+}
+
+
void CodeFlusher::EvictJSFunctionCandidates() {
JSFunction* candidate = jsfunction_candidates_head_;
JSFunction* next_candidate;
@@ -1136,6 +1230,18 @@
}
+void CodeFlusher::EvictOptimizedCodeMaps() {
+ SharedFunctionInfo* holder = optimized_code_map_holder_head_;
+ SharedFunctionInfo* next_holder;
+ while (holder != NULL) {
+ next_holder = GetNextCodeMap(holder);
+ EvictOptimizedCodeMap(holder);
+ holder = next_holder;
+ }
+ ASSERT(optimized_code_map_holder_head_ == NULL);
+}
+
+
void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) {
Heap* heap = isolate_->heap();
@@ -3955,6 +4061,10 @@
delete code_flusher_;
code_flusher_ = NULL;
}
+
+ if (FLAG_trace_code_flushing) {
+ PrintF("[code-flushing is now %s]\n", enable ? "on" : "off");
+ }
}
diff --git a/src/mark-compact.h b/src/mark-compact.h
index cbc8f41..0f20440 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -406,9 +406,10 @@
// CodeFlusher collects candidates for code flushing during marking and
// processes those candidates after marking has completed in order to
// reset those functions referencing code objects that would otherwise
-// be unreachable. Code objects can be referenced in two ways:
+// be unreachable. Code objects can be referenced in three ways:
// - SharedFunctionInfo references unoptimized code.
// - JSFunction references either unoptimized or optimized code.
+// - OptimizedCodeMap references optimized code.
// We are not allowed to flush unoptimized code for functions that got
// optimized or inlined into optimized code, because we might bailout
// into the unoptimized code again during deoptimization.
@@ -417,7 +418,8 @@
explicit CodeFlusher(Isolate* isolate)
: isolate_(isolate),
jsfunction_candidates_head_(NULL),
- shared_function_info_candidates_head_(NULL) {}
+ shared_function_info_candidates_head_(NULL),
+ optimized_code_map_holder_head_(NULL) {}
void AddCandidate(SharedFunctionInfo* shared_info) {
if (GetNextCandidate(shared_info) == NULL) {
@@ -434,15 +436,25 @@
}
}
+ void AddOptimizedCodeMap(SharedFunctionInfo* code_map_holder) {
+ if (GetNextCodeMap(code_map_holder)->IsUndefined()) {
+ SetNextCodeMap(code_map_holder, optimized_code_map_holder_head_);
+ optimized_code_map_holder_head_ = code_map_holder;
+ }
+ }
+
+ void EvictOptimizedCodeMap(SharedFunctionInfo* code_map_holder);
void EvictCandidate(SharedFunctionInfo* shared_info);
void EvictCandidate(JSFunction* function);
void ProcessCandidates() {
+ ProcessOptimizedCodeMaps();
ProcessSharedFunctionInfoCandidates();
ProcessJSFunctionCandidates();
}
void EvictAllCandidates() {
+ EvictOptimizedCodeMaps();
EvictJSFunctionCandidates();
EvictSharedFunctionInfoCandidates();
}
@@ -450,8 +462,10 @@
void IteratePointersToFromSpace(ObjectVisitor* v);
private:
+ void ProcessOptimizedCodeMaps();
void ProcessJSFunctionCandidates();
void ProcessSharedFunctionInfoCandidates();
+ void EvictOptimizedCodeMaps();
void EvictJSFunctionCandidates();
void EvictSharedFunctionInfoCandidates();
@@ -489,9 +503,27 @@
candidate->code()->set_gc_metadata(NULL, SKIP_WRITE_BARRIER);
}
+ static SharedFunctionInfo* GetNextCodeMap(SharedFunctionInfo* holder) {
+ FixedArray* code_map = FixedArray::cast(holder->optimized_code_map());
+ Object* next_map = code_map->get(SharedFunctionInfo::kNextMapIndex);
+ return reinterpret_cast<SharedFunctionInfo*>(next_map);
+ }
+
+ static void SetNextCodeMap(SharedFunctionInfo* holder,
+ SharedFunctionInfo* next_holder) {
+ FixedArray* code_map = FixedArray::cast(holder->optimized_code_map());
+ code_map->set(SharedFunctionInfo::kNextMapIndex, next_holder);
+ }
+
+ static void ClearNextCodeMap(SharedFunctionInfo* holder) {
+ FixedArray* code_map = FixedArray::cast(holder->optimized_code_map());
+ code_map->set_undefined(SharedFunctionInfo::kNextMapIndex);
+ }
+
Isolate* isolate_;
JSFunction* jsfunction_candidates_head_;
SharedFunctionInfo* shared_function_info_candidates_head_;
+ SharedFunctionInfo* optimized_code_map_holder_head_;
DISALLOW_COPY_AND_ASSIGN(CodeFlusher);
};
diff --git a/src/messages.js b/src/messages.js
index b9bce1e..296965d 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -98,7 +98,10 @@
observe_non_object: ["Object.", "%0", " cannot ", "%0", " non-object"],
observe_non_function: ["Object.", "%0", " cannot deliver to non-function"],
observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"],
+ observe_invalid_accept: ["Object.observe accept must be an array of strings."],
observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"],
+ observe_perform_non_string: ["Invalid non-string changeType"],
+ observe_perform_non_function: ["Cannot perform non-function"],
observe_notify_non_notifier: ["notify called on non-notifier object"],
proto_poison_pill: ["Generic use of __proto__ accessor not allowed"],
parameterless_typed_array_constr:
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index f1c2553..7c09bb3 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -309,8 +309,8 @@
// The optimized code map must never be empty, so check the first elements.
Label install_optimized;
// Speculatively move code object into t0.
- __ lw(t0, FieldMemOperand(a1, FixedArray::kHeaderSize + kPointerSize));
- __ lw(t1, FieldMemOperand(a1, FixedArray::kHeaderSize));
+ __ lw(t0, FieldMemOperand(a1, SharedFunctionInfo::kFirstCodeSlot));
+ __ lw(t1, FieldMemOperand(a1, SharedFunctionInfo::kFirstContextSlot));
__ Branch(&install_optimized, eq, a2, Operand(t1));
// Iterate through the rest of map backwards. t0 holds an index as a Smi.
@@ -318,11 +318,9 @@
__ lw(t0, FieldMemOperand(a1, FixedArray::kLengthOffset));
__ bind(&loop);
// Do not double check first entry.
-
__ Branch(&install_unoptimized, eq, t0,
- Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
- __ Subu(t0, t0, Operand(
- Smi::FromInt(SharedFunctionInfo::kEntryLength))); // Skip an entry.
+ Operand(Smi::FromInt(SharedFunctionInfo::kSecondEntryIndex)));
+ __ Subu(t0, t0, Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
__ Addu(t1, a1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ sll(at, t0, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t1, t1, Operand(at));
@@ -2400,8 +2398,12 @@
GenerateTypeTransition(masm);
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2426,7 +2428,8 @@
__ GetObjectType(right, a2, a2);
__ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
+ StringAddStub string_add_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_stub);
@@ -2746,8 +2749,12 @@
}
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2794,8 +2801,12 @@
GenerateTypeTransition(masm);
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2818,8 +2829,12 @@
}
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -2835,7 +2850,8 @@
__ GetObjectType(left, a2, a2);
__ Branch(&left_not_string, ge, a2, Operand(FIRST_NONSTRING_TYPE));
- StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
+ StringAddStub string_add_left_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_left_stub);
@@ -2845,7 +2861,8 @@
__ GetObjectType(right, a2, a2);
__ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
- StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
+ StringAddStub string_add_right_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB));
GenerateRegisterArgsPush(masm);
__ TailCallStub(&string_add_right_stub);
@@ -5139,6 +5156,7 @@
__ bind(&megamorphic);
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+ __ jmp(&done);
// An uninitialized cache is patched with the function or sentinel to
// indicate the ElementsKind if function is the Array constructor.
@@ -6181,7 +6199,7 @@
__ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
// Make sure that both arguments are strings if not known in advance.
- if (flags_ == NO_STRING_ADD_FLAGS) {
+ if ((flags_ & NO_STRING_ADD_FLAGS) != 0) {
__ JumpIfEitherSmi(a0, a1, &call_runtime);
// Load instance types.
__ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
@@ -6470,15 +6488,49 @@
// Just jump to runtime to add the two strings.
__ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm);
+ // Build a frame.
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ CallRuntime(Runtime::kStringAdd, 2);
+ }
+ __ Ret();
+ } else {
+ __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ }
if (call_builtin.is_linked()) {
__ bind(&call_builtin);
- __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm);
+ // Build a frame.
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(builtin_id, CALL_FUNCTION);
+ }
+ __ Ret();
+ } else {
+ __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ }
}
}
+void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+ __ push(a0);
+ __ push(a1);
+}
+
+
+void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
+ __ pop(a1);
+ __ pop(a0);
+}
+
+
void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
int stack_offset,
Register arg,
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index 3a84644..ec7d147 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -212,11 +212,13 @@
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
- NO_STRING_ADD_FLAGS = 0,
+ NO_STRING_ADD_FLAGS = 1 << 0,
// Omit left string check in stub (left is definitely a string).
- NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
+ NO_STRING_CHECK_LEFT_IN_STUB = 1 << 1,
// Omit right string check in stub (right is definitely a string).
- NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
+ NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 2,
+ // Stub needs a frame before calling the runtime
+ ERECT_FRAME = 1 << 3,
// Omit both string checks in stub.
NO_STRING_CHECK_IN_STUB =
NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
@@ -242,6 +244,9 @@
Register scratch4,
Label* slow);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateRegisterArgsPop(MacroAssembler* masm);
+
const StringAddFlags flags_;
};
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 422312f..31fad2b 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -266,7 +266,7 @@
if (FLAG_trace_osr) {
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => node=%u, frame=%d->%d]\n",
ast_id,
input_frame_size,
@@ -360,190 +360,12 @@
PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
ok ? "finished" : "aborted",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
}
}
-// This code is very similar to ia32/arm code, but relies on register names
-// (fp, sp) and how the frame is laid out.
-void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
- int frame_index) {
- // Read the ast node id, function, and frame height for this output frame.
- BailoutId node_id = BailoutId(iterator->Next());
- JSFunction* function;
- if (frame_index != 0) {
- function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- } else {
- int closure_id = iterator->Next();
- USE(closure_id);
- ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
- function = function_;
- }
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating ");
- function->PrintName();
- PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
- }
-
- // The 'fixed' part of the frame consists of the incoming parameters and
- // the part described by JavaScriptFrameConstants.
- unsigned fixed_frame_size = ComputeFixedSize(function);
- unsigned input_frame_size = input_->GetFrameSize();
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
-
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
- ASSERT(frame_index >= 0 && frame_index < output_count_);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address for the bottommost output frame can be computed from
- // the input frame pointer and the output frame's height. For all
- // subsequent output frames, it can be computed from the previous one's
- // top address and the current frame's size.
- uint32_t top_address;
- if (is_bottommost) {
- // 2 = context and function in the frame.
- top_address =
- input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = function->shared()->formal_parameter_count() + 1;
- unsigned output_offset = output_frame_size;
- unsigned input_offset = input_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- input_offset -= (parameter_count * kPointerSize);
-
- // There are no translation commands for the caller's pc and fp, the
- // context, and the function. Synthesize their values and set them up
- // explicitly.
- //
- // The caller's pc for the bottommost output frame is the same as in the
- // input frame. For all subsequent output frames, it can be read from the
- // previous one. This frame's pc can be computed from the non-optimized
- // function code and AST id of the bailout.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- intptr_t value;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetPc();
- }
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The caller's frame pointer for the bottommost output frame is the same
- // as in the input frame. For all subsequent output frames, it can be
- // read from the previous one. Also compute and set this frame's frame
- // pointer.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetFp();
- }
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value);
- output_frame->SetFp(fp_value);
- if (is_topmost) {
- output_frame->SetRegister(fp.code(), fp_value);
- }
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // For the bottommost output frame the context can be gotten from the input
- // frame. For all subsequent output frames it can be gotten from the function
- // so long as we don't inline functions that need local contexts.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = reinterpret_cast<intptr_t>(function->context());
- }
- output_frame->SetFrameSlot(output_offset, value);
- output_frame->SetContext(value);
- if (is_topmost) output_frame->SetRegister(cp.code(), value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The function was mentioned explicitly in the BEGIN_FRAME.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(function);
- // The function for the bottommost output frame should also agree with the
- // input frame.
- ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Translate the rest of the frame.
- for (unsigned i = 0; i < height; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- ASSERT(0 == output_offset);
-
- // Compute this frame's PC, state, and continuation.
- Code* non_optimized_code = function->shared()->code();
- FixedArray* raw_data = non_optimized_code->deoptimization_data();
- DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
- Address start = non_optimized_code->instruction_start();
- unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
- unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
- uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
- output_frame->SetPc(pc_value);
-
- FullCodeGenerator::State state =
- FullCodeGenerator::StateField::decode(pc_and_state);
- output_frame->SetState(Smi::FromInt(state));
-
-
- // Set the continuation for the topmost frame.
- if (is_topmost && bailout_type_ != DEBUGGER) {
- Builtins* builtins = isolate_->builtins();
- Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
- if (bailout_type_ == LAZY) {
- continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
- } else if (bailout_type_ == SOFT) {
- continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
- } else {
- ASSERT(bailout_type_ == EAGER);
- }
- output_frame->SetContinuation(
- reinterpret_cast<uint32_t>(continuation->entry()));
- }
-}
-
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
@@ -588,6 +410,12 @@
}
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+ // There is no dynamic alignment padding on MIPS in the input frame.
+ return false;
+}
+
+
#define __ masm()->
diff --git a/src/mips/frames-mips.cc b/src/mips/frames-mips.cc
index 79505ae..540caa9 100644
--- a/src/mips/frames-mips.cc
+++ b/src/mips/frames-mips.cc
@@ -47,6 +47,10 @@
}
+Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
+Register JavaScriptFrame::context_register() { return cp; }
+
+
Register StubFailureTrampolineFrame::fp_register() { return v8::internal::fp; }
Register StubFailureTrampolineFrame::context_register() { return cp; }
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 872af86..bdfa43b 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -179,6 +179,7 @@
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
// Adjust fp to point to caller's fp.
__ Addu(fp, sp, Operand(2 * kPointerSize));
+ info->AddNoFrameRange(0, masm_->pc_offset());
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
@@ -438,9 +439,11 @@
CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
__ RecordJSReturn();
masm_->mov(sp, fp);
+ int no_frame_start = masm_->pc_offset();
masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit()));
masm_->Addu(sp, sp, Operand(sp_delta));
masm_->Jump(ra);
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
}
#ifdef DEBUG
@@ -1965,8 +1968,108 @@
break;
}
- case Yield::DELEGATING:
- UNIMPLEMENTED();
+ case Yield::DELEGATING: {
+ VisitForStackValue(expr->generator_object());
+
+ // Initial stack layout is as follows:
+ // [sp + 1 * kPointerSize] iter
+ // [sp + 0 * kPointerSize] g
+
+ Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+ // Initial send value is undefined.
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
+ __ Branch(&l_send);
+
+ // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
+ __ bind(&l_catch);
+ __ mov(a0, v0);
+ handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+ __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
+ __ push(a3); // iter
+ __ push(a0); // exception
+ __ mov(a0, a3); // iter
+ __ push(a0); // push LoadIC state
+ __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
+ Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(throw_ic); // iter.throw in a0
+ __ mov(a0, v0);
+ __ Addu(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+ __ jmp(&l_call);
+
+ // try { received = yield result.value }
+ __ bind(&l_try);
+ __ pop(a0); // result.value
+ __ PushTryHandler(StackHandler::CATCH, expr->index());
+ const int handler_size = StackHandlerConstants::kSize;
+ __ push(a0); // result.value
+ __ lw(a3, MemOperand(sp, (0 + 1) * kPointerSize + handler_size)); // g
+ __ push(a3); // g
+ __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+ __ mov(a0, v0);
+ __ lw(context_register(),
+ MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ Branch(&l_resume, ne, a0, Operand(at));
+ EmitReturnIteratorResult(false);
+ __ mov(a0, v0);
+ __ bind(&l_resume); // received in a0
+ __ PopTryHandler();
+
+ // receiver = iter; f = iter.send; arg = received;
+ __ bind(&l_send);
+ __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
+ __ push(a3); // iter
+ __ push(a0); // received
+ __ mov(a0, a3); // iter
+ __ push(a0); // push LoadIC state
+ __ LoadRoot(a2, Heap::ksend_stringRootIndex); // "send"
+ Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(send_ic); // iter.send in a0
+ __ mov(a0, v0);
+ __ Addu(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+
+ // result = f.call(receiver, arg);
+ __ bind(&l_call);
+ Label l_call_runtime;
+ __ JumpIfSmi(a0, &l_call_runtime);
+ __ GetObjectType(a0, a1, a1);
+ __ Branch(&l_call_runtime, ne, a1, Operand(JS_FUNCTION_TYPE));
+ __ mov(a1, a0);
+ ParameterCount count(1);
+ __ InvokeFunction(a1, count, CALL_FUNCTION,
+ NullCallWrapper(), CALL_AS_METHOD);
+ __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ jmp(&l_loop);
+ __ bind(&l_call_runtime);
+ __ push(a0);
+ __ CallRuntime(Runtime::kCall, 3);
+
+ // val = result.value; if (!result.done) goto l_try;
+ __ bind(&l_loop);
+ __ mov(a0, v0);
+ // result.value
+ __ push(a0); // save result
+ __ LoadRoot(a2, Heap::kvalue_stringRootIndex); // "value"
+ Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(value_ic); // result.value in a0
+ __ mov(a0, v0);
+ __ pop(a1); // result
+ __ push(a0); // result.value
+ __ mov(a0, a1); // result
+ __ push(a0); // push LoadIC state
+ __ LoadRoot(a2, Heap::kdone_stringRootIndex); // "done"
+ Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(done_ic); // result.done in v0
+ __ Addu(sp, sp, Operand(kPointerSize)); // drop LoadIC state
+ ToBooleanStub stub(v0);
+ __ CallStub(&stub);
+ __ Branch(&l_try, eq, v0, Operand(zero_reg));
+
+ // result.value
+ __ pop(v0); // result.value
+ context()->DropAndPlug(2, v0); // drop iter and g
+ break;
+ }
}
}
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index bcb940a..ae0d628 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -179,6 +179,7 @@
__ Addu(fp, sp, Operand(2 * kPointerSize));
}
frame_is_built_ = true;
+ info_->AddNoFrameRange(0, masm_->pc_offset());
}
// Reserve space for the stack slots needed by the code.
@@ -1826,6 +1827,11 @@
}
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
+ __ stop("LDebugBreak");
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2050,48 +2056,6 @@
}
-
-void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
- Register scratch = scratch0();
- Register reg = ToRegister(instr->value());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- // If the expression is known to be untagged or a smi, then it's definitely
- // not null, and it can't be a an undetectable object.
- if (instr->hydrogen()->representation().IsSpecialization() ||
- instr->hydrogen()->type().IsSmi()) {
- EmitGoto(false_block);
- return;
- }
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
-
- Heap::RootListIndex nil_value = instr->nil() == kNullValue ?
- Heap::kNullValueRootIndex :
- Heap::kUndefinedValueRootIndex;
- __ LoadRoot(at, nil_value);
- if (instr->kind() == kStrictEquality) {
- EmitBranch(true_block, false_block, eq, reg, Operand(at));
- } else {
- Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ?
- Heap::kUndefinedValueRootIndex :
- Heap::kNullValueRootIndex;
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ Branch(USE_DELAY_SLOT, true_label, eq, reg, Operand(at));
- __ LoadRoot(at, other_nil_value); // In the delay slot.
- __ Branch(USE_DELAY_SLOT, true_label, eq, reg, Operand(at));
- __ JumpIfSmi(reg, false_label); // In the delay slot.
- // Check for undetectable objects by looking in the bit field in
- // the map. The object has already been smi checked.
- __ lw(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ lbu(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
- __ And(scratch, scratch, 1 << Map::kIsUndetectable);
- EmitBranch(true_block, false_block, ne, scratch, Operand(zero_reg));
- }
-}
-
-
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Register temp2,
@@ -2570,9 +2534,11 @@
count++;
}
}
+ int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ mov(sp, fp);
__ Pop(ra, fp);
+ no_frame_start = masm_->pc_offset();
}
if (instr->has_constant_parameter_count()) {
int parameter_count = ToInteger32(instr->constant_parameter_count());
@@ -2589,6 +2555,10 @@
}
__ Jump(ra);
+
+ if (no_frame_start != -1) {
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+ }
}
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index b5c47ef..5ca8cd9 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -208,6 +208,10 @@
}
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+ return new(zone()) LDebugBreak();
+}
+
void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
@@ -217,15 +221,6 @@
}
-void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if ");
- value()->PrintTo(stream);
- stream->Add(kind() == kStrictEquality ? " === " : " == ");
- stream->Add(nil() == kNullValue ? "null" : "undefined");
- stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
value()->PrintTo(stream);
@@ -1592,12 +1587,6 @@
}
-LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()));
-}
-
-
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* temp = TempRegister();
@@ -1710,7 +1699,7 @@
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegister(instr->index());
- LOperand* value = UseRegister(instr->value());
+ LOperand* value = UseTempRegister(instr->value());
LSeqStringSetChar* result =
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
return DefineAsRegister(result);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 7dcb50e..1abea90 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -89,6 +89,7 @@
V(ConstantI) \
V(ConstantT) \
V(Context) \
+ V(DebugBreak) \
V(DeclareGlobals) \
V(DeleteProperty) \
V(Deoptimize) \
@@ -113,7 +114,6 @@
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
- V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
@@ -656,6 +656,12 @@
};
+class LDebugBreak: public LTemplateInstruction<0, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
@@ -847,24 +853,6 @@
};
-class LIsNilAndBranch: public LControlInstruction<1, 0> {
- public:
- explicit LIsNilAndBranch(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
-
- EqualityKind kind() const { return hydrogen()->kind(); }
- NilValue nil() const { return hydrogen()->nil(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsObjectAndBranch: public LControlInstruction<1, 1> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 4673458..ffc8679 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -526,7 +526,7 @@
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
int value = *cur;
Heap* current_heap = v8::internal::Isolate::Current()->heap();
- if (current_heap->Contains(obj) || ((value & 1) == 0)) {
+ if (((value & 1) == 0) || current_heap->Contains(obj)) {
PrintF(" (");
if ((value & 1) == 0) {
PrintF("smi %d", value / 2);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 5b36cc2..90ae404 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -621,7 +621,6 @@
} else {
ASSERT(storage_reg.is(name_reg));
}
- __ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
offset,
name_reg,
diff --git a/src/object-observe.js b/src/object-observe.js
index 77409b9..b28f928 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -66,18 +66,147 @@
var info = {
changeObservers: new InternalArray,
notifier: null,
+ inactiveObservers: new InternalArray,
+ performing: { __proto__: null },
+ performingCount: 0,
};
objectInfoMap.set(object, info);
return info;
}
-function ObjectObserve(object, callback) {
+var defaultAcceptTypes = {
+ __proto__: null,
+ 'new': true,
+ 'updated': true,
+ 'deleted': true,
+ 'prototype': true,
+ 'reconfigured': true
+};
+
+function CreateObserver(callback, accept) {
+ var observer = {
+ __proto__: null,
+ callback: callback,
+ accept: defaultAcceptTypes
+ };
+
+ if (IS_UNDEFINED(accept))
+ return observer;
+
+ var acceptMap = { __proto__: null };
+ for (var i = 0; i < accept.length; i++)
+ acceptMap[accept[i]] = true;
+
+ observer.accept = acceptMap;
+ return observer;
+}
+
+function ObserverIsActive(observer, objectInfo) {
+ if (objectInfo.performingCount === 0)
+ return true;
+
+ var performing = objectInfo.performing;
+ for (var type in performing) {
+ if (performing[type] > 0 && observer.accept[type])
+ return false;
+ }
+
+ return true;
+}
+
+function ObserverIsInactive(observer, objectInfo) {
+ return !ObserverIsActive(observer, objectInfo);
+}
+
+function RemoveNullElements(from) {
+ var i = 0;
+ var j = 0;
+ for (; i < from.length; i++) {
+ if (from[i] === null)
+ continue;
+ if (j < i)
+ from[j] = from[i];
+ j++;
+ }
+
+ if (i !== j)
+ from.length = from.length - (i - j);
+}
+
+function RepartitionObservers(conditionFn, from, to, objectInfo) {
+ var anyRemoved = false;
+ for (var i = 0; i < from.length; i++) {
+ var observer = from[i];
+ if (conditionFn(observer, objectInfo)) {
+ anyRemoved = true;
+ from[i] = null;
+ to.push(observer);
+ }
+ }
+
+ if (anyRemoved)
+ RemoveNullElements(from);
+}
+
+function BeginPerformChange(objectInfo, type) {
+ objectInfo.performing[type] = (objectInfo.performing[type] || 0) + 1;
+ objectInfo.performingCount++;
+ RepartitionObservers(ObserverIsInactive,
+ objectInfo.changeObservers,
+ objectInfo.inactiveObservers,
+ objectInfo);
+}
+
+function EndPerformChange(objectInfo, type) {
+ objectInfo.performing[type]--;
+ objectInfo.performingCount--;
+ RepartitionObservers(ObserverIsActive,
+ objectInfo.inactiveObservers,
+ objectInfo.changeObservers,
+ objectInfo);
+}
+
+function EnsureObserverRemoved(objectInfo, callback) {
+ function remove(observerList) {
+ for (var i = 0; i < observerList.length; i++) {
+ if (observerList[i].callback === callback) {
+ observerList.splice(i, 1);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (!remove(objectInfo.changeObservers))
+ remove(objectInfo.inactiveObservers);
+}
+
+function AcceptArgIsValid(arg) {
+ if (IS_UNDEFINED(arg))
+ return true;
+
+ if (!IS_SPEC_OBJECT(arg) ||
+ !IS_NUMBER(arg.length) ||
+ arg.length < 0)
+ return false;
+
+ var length = arg.length;
+ for (var i = 0; i < length; i++) {
+ if (!IS_STRING(arg[i]))
+ return false;
+ }
+ return true;
+}
+
+function ObjectObserve(object, callback, accept) {
if (!IS_SPEC_OBJECT(object))
throw MakeTypeError("observe_non_object", ["observe"]);
if (!IS_SPEC_FUNCTION(callback))
throw MakeTypeError("observe_non_function", ["observe"]);
if (ObjectIsFrozen(callback))
throw MakeTypeError("observe_callback_frozen");
+ if (!AcceptArgIsValid(accept))
+ throw MakeTypeError("observe_accept_invalid");
if (!observerInfoMap.has(callback)) {
observerInfoMap.set(callback, {
@@ -90,8 +219,13 @@
if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object);
%SetIsObserved(object, true);
- var changeObservers = objectInfo.changeObservers;
- if (changeObservers.indexOf(callback) < 0) changeObservers.push(callback);
+ EnsureObserverRemoved(objectInfo, callback);
+
+ var observer = CreateObserver(callback, accept);
+ if (ObserverIsActive(observer, objectInfo))
+ objectInfo.changeObservers.push(observer);
+ else
+ objectInfo.inactiveObservers.push(observer);
return object;
}
@@ -106,24 +240,39 @@
if (IS_UNDEFINED(objectInfo))
return object;
- var changeObservers = objectInfo.changeObservers;
- var index = changeObservers.indexOf(callback);
- if (index >= 0) {
- changeObservers.splice(index, 1);
- if (changeObservers.length === 0) %SetIsObserved(object, false);
+ EnsureObserverRemoved(objectInfo, callback);
+
+ if (objectInfo.changeObservers.length === 0 &&
+ objectInfo.inactiveObservers.length === 0) {
+ %SetIsObserved(object, false);
}
return object;
}
+function ArrayObserve(object, callback) {
+ return ObjectObserve(object, callback, ['new',
+ 'updated',
+ 'deleted',
+ 'splice']);
+}
+
+function ArrayUnobserve(object, callback) {
+ return ObjectUnobserve(object, callback);
+}
+
function EnqueueChangeRecord(changeRecord, observers) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(changeRecord.name)) return;
for (var i = 0; i < observers.length; i++) {
var observer = observers[i];
- var observerInfo = observerInfoMap.get(observer);
- observationState.pendingObservers[observerInfo.priority] = observer;
+ if (IS_UNDEFINED(observer.accept[changeRecord.type]))
+ continue;
+
+ var callback = observer.callback;
+ var observerInfo = observerInfoMap.get(callback);
+ observationState.pendingObservers[observerInfo.priority] = callback;
%SetObserverDeliveryPending();
if (IS_NULL(observerInfo.pendingChangeRecords)) {
observerInfo.pendingChangeRecords = new InternalArray(changeRecord);
@@ -133,8 +282,44 @@
}
}
+function BeginPerformSplice(array) {
+ var objectInfo = objectInfoMap.get(array);
+ if (!IS_UNDEFINED(objectInfo))
+ BeginPerformChange(objectInfo, 'splice');
+}
+
+function EndPerformSplice(array) {
+ var objectInfo = objectInfoMap.get(array);
+ if (!IS_UNDEFINED(objectInfo))
+ EndPerformChange(objectInfo, 'splice');
+}
+
+function EnqueueSpliceRecord(array, index, removed, deleteCount, addedCount) {
+ var objectInfo = objectInfoMap.get(array);
+ if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
+ return;
+
+ var changeRecord = {
+ type: 'splice',
+ object: array,
+ index: index,
+ removed: removed,
+ addedCount: addedCount
+ };
+
+ changeRecord.removed.length = deleteCount;
+ // TODO(rafaelw): This breaks spec-compliance. Re-enable when freezing isn't
+ // slow.
+ // ObjectFreeze(changeRecord);
+ // ObjectFreeze(changeRecord.removed);
+ EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
+}
+
function NotifyChange(type, object, name, oldValue) {
var objectInfo = objectInfoMap.get(object);
+ if (objectInfo.changeObservers.length === 0)
+ return;
+
var changeRecord = (arguments.length < 4) ?
{ type: type, object: object, name: name } :
{ type: type, object: object, name: name, oldValue: oldValue };
@@ -173,6 +358,36 @@
EnqueueChangeRecord(newRecord, objectInfo.changeObservers);
}
+function ObjectNotifierPerformChange(changeType, changeFn, receiver) {
+ if (!IS_SPEC_OBJECT(this))
+ throw MakeTypeError("called_on_non_object", ["performChange"]);
+
+ var target = notifierTargetMap.get(this);
+ if (IS_UNDEFINED(target))
+ throw MakeTypeError("observe_notify_non_notifier");
+ if (!IS_STRING(changeType))
+ throw MakeTypeError("observe_perform_non_string");
+ if (!IS_SPEC_FUNCTION(changeFn))
+ throw MakeTypeError("observe_perform_non_function");
+
+ if (IS_NULL_OR_UNDEFINED(receiver)) {
+ receiver = %GetDefaultReceiver(changeFn) || receiver;
+ } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(changeFn)) {
+ receiver = ToObject(receiver);
+ }
+
+ var objectInfo = objectInfoMap.get(target);
+ if (IS_UNDEFINED(objectInfo))
+ return;
+
+ BeginPerformChange(objectInfo, changeType);
+ try {
+ %_CallFunction(receiver, changeFn);
+ } finally {
+ EndPerformChange(objectInfo, changeType);
+ }
+}
+
function ObjectGetNotifier(object) {
if (!IS_SPEC_OBJECT(object))
throw MakeTypeError("observe_non_object", ["getNotifier"]);
@@ -234,8 +449,13 @@
"observe", ObjectObserve,
"unobserve", ObjectUnobserve
));
+ InstallFunctions($Array, DONT_ENUM, $Array(
+ "observe", ArrayObserve,
+ "unobserve", ArrayUnobserve
+ ));
InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
- "notify", ObjectNotifierNotify
+ "notify", ObjectNotifierNotify,
+ "performChange", ObjectNotifierPerformChange
));
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 7628cf2..8c6e925 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1484,10 +1484,17 @@
void JSObject::initialize_elements() {
- ASSERT(map()->has_fast_smi_or_object_elements() ||
- map()->has_fast_double_elements());
- ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
- WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
+ if (map()->has_fast_smi_or_object_elements() ||
+ map()->has_fast_double_elements()) {
+ ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
+ WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
+ } else if (map()->has_external_array_elements()) {
+ ExternalArray* empty_array = GetHeap()->EmptyExternalArrayForMap(map());
+ ASSERT(!GetHeap()->InNewSpace(empty_array));
+ WRITE_FIELD(this, kElementsOffset, empty_array);
+ } else {
+ UNREACHABLE();
+ }
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 0849a63..ddecae3 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -596,8 +596,8 @@
}
PrintF(out, " - back pointer: ");
GetBackPointer()->ShortPrint(out);
- PrintF(out, "\n - instance descriptors %i #%i: ",
- owns_descriptors(),
+ PrintF(out, "\n - instance descriptors %s#%i: ",
+ owns_descriptors() ? "(own) " : "",
NumberOfOwnDescriptors());
instance_descriptors()->ShortPrint(out);
if (HasTransitionArray()) {
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index d2bf65e..f83f00f 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -311,15 +311,23 @@
if (shared->ic_age() != heap->global_ic_age()) {
shared->ResetForNewContext(heap->global_ic_age());
}
- if (FLAG_cache_optimized_code) {
- // Flush optimized code map on major GC.
- // TODO(mstarzinger): We may experiment with rebuilding it or with
- // retaining entries which should survive as we iterate through
- // optimized functions anyway.
- shared->ClearOptimizedCodeMap("during full gc");
+ if (FLAG_cache_optimized_code &&
+ FLAG_flush_optimized_code_cache &&
+ !shared->optimized_code_map()->IsSmi()) {
+ // Always flush the optimized code map if requested by flag.
+ shared->ClearOptimizedCodeMap();
}
MarkCompactCollector* collector = heap->mark_compact_collector();
if (collector->is_code_flushing_enabled()) {
+ if (FLAG_cache_optimized_code && !shared->optimized_code_map()->IsSmi()) {
+ // Add the shared function info holding an optimized code map to
+ // the code flusher for processing of code maps after marking.
+ collector->code_flusher()->AddOptimizedCodeMap(shared);
+ // Treat all references within the code map weakly by marking the
+ // code map itself but not pushing it onto the marking deque.
+ FixedArray* code_map = FixedArray::cast(shared->optimized_code_map());
+ StaticVisitor::MarkObjectWithoutPush(heap, code_map);
+ }
if (IsFlushable(heap, shared)) {
// This function's code looks flushable. But we have to postpone
// the decision until we see all functions that point to the same
@@ -332,6 +340,12 @@
VisitSharedFunctionInfoWeakCode(heap, object);
return;
}
+ } else {
+ if (FLAG_cache_optimized_code && !shared->optimized_code_map()->IsSmi()) {
+ // Flush optimized code map on major GCs without code flushing,
+ // needed because cached code doesn't contain breakpoints.
+ shared->ClearOptimizedCodeMap();
+ }
}
VisitSharedFunctionInfoStrongCode(heap, object);
}
diff --git a/src/objects.cc b/src/objects.cc
index 53774d7..ee0ff51 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2186,7 +2186,7 @@
Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) {
- ZapEndOfFixedArray(new_end, to_trim);
+ ZapEndOfFixedArray(new_end, to_trim);
}
int size_delta = to_trim * kPointerSize;
@@ -2437,6 +2437,7 @@
}
+// Returns NULL if the updated map is incompatible.
Map* Map::FindUpdatedMap(int verbatim,
int length,
DescriptorArray* descriptors) {
@@ -2452,6 +2453,17 @@
int transition = transitions->Search(name);
if (transition == TransitionArray::kNotFound) break;
current = transitions->GetTarget(transition);
+ PropertyDetails details = descriptors->GetDetails(i);
+ PropertyDetails target_details =
+ current->instance_descriptors()->GetDetails(i);
+ if (details.attributes() != target_details.attributes()) return NULL;
+ if (details.type() == CALLBACKS) {
+ if (target_details.type() != CALLBACKS) return NULL;
+ if (descriptors->GetValue(i) !=
+ current->instance_descriptors()->GetValue(i)) {
+ return NULL;
+ }
+ }
}
return current;
@@ -2534,6 +2546,8 @@
Map* updated = root_map->FindUpdatedMap(
verbatim, descriptors, old_descriptors);
+ if (updated == NULL) return CopyGeneralizeAllRepresentations();
+
// Check the state of the root map.
DescriptorArray* updated_descriptors = updated->instance_descriptors();
@@ -7509,19 +7523,13 @@
for (int descriptor = verbatim; descriptor < valid; descriptor++) {
PropertyDetails details = GetDetails(descriptor);
PropertyDetails other_details = other->GetDetails(descriptor);
- if (details.type() != other_details.type()) {
- if (details.type() != FIELD ||
- other_details.type() != CONSTANT_FUNCTION) {
- return false;
- }
- } else if (details.type() == CONSTANT_FUNCTION) {
- if (GetValue(descriptor) != other->GetValue(descriptor)) {
- return false;
- }
- } else if (!other_details.representation().fits_into(
- details.representation())) {
+ if (!other_details.representation().fits_into(details.representation())) {
return false;
}
+ if (details.type() == CONSTANT_FUNCTION) {
+ if (other_details.type() != CONSTANT_FUNCTION) return false;
+ if (GetValue(descriptor) != other->GetValue(descriptor)) return false;
+ }
}
return true;
@@ -8976,33 +8984,46 @@
Handle<Context> native_context,
Handle<Code> code,
Handle<FixedArray> literals) {
+ CALL_HEAP_FUNCTION_VOID(
+ shared->GetIsolate(),
+ shared->AddToOptimizedCodeMap(*native_context, *code, *literals));
+}
+
+
+MaybeObject* SharedFunctionInfo::AddToOptimizedCodeMap(Context* native_context,
+ Code* code,
+ FixedArray* literals) {
ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
ASSERT(native_context->IsNativeContext());
STATIC_ASSERT(kEntryLength == 3);
- Object* value = shared->optimized_code_map();
- Handle<FixedArray> new_code_map;
+ Heap* heap = GetHeap();
+ FixedArray* new_code_map;
+ Object* value = optimized_code_map();
if (value->IsSmi()) {
// No optimized code map.
ASSERT_EQ(0, Smi::cast(value)->value());
// Crate 3 entries per context {context, code, literals}.
- new_code_map = FACTORY->NewFixedArray(kEntryLength);
- new_code_map->set(0, *native_context);
- new_code_map->set(1, *code);
- new_code_map->set(2, *literals);
+ MaybeObject* maybe = heap->AllocateFixedArray(kInitialLength);
+ if (!maybe->To(&new_code_map)) return maybe;
+ new_code_map->set(kEntriesStart + 0, native_context);
+ new_code_map->set(kEntriesStart + 1, code);
+ new_code_map->set(kEntriesStart + 2, literals);
} else {
// Copy old map and append one new entry.
- Handle<FixedArray> old_code_map(FixedArray::cast(value));
- ASSERT_EQ(-1, shared->SearchOptimizedCodeMap(*native_context));
+ FixedArray* old_code_map = FixedArray::cast(value);
+ ASSERT_EQ(-1, SearchOptimizedCodeMap(native_context));
int old_length = old_code_map->length();
int new_length = old_length + kEntryLength;
- new_code_map = FACTORY->NewFixedArray(new_length);
- old_code_map->CopyTo(0, *new_code_map, 0, old_length);
- new_code_map->set(old_length, *native_context);
- new_code_map->set(old_length + 1, *code);
- new_code_map->set(old_length + 2, *literals);
+ MaybeObject* maybe = old_code_map->CopySize(new_length);
+ if (!maybe->To(&new_code_map)) return maybe;
+ new_code_map->set(old_length + 0, native_context);
+ new_code_map->set(old_length + 1, code);
+ new_code_map->set(old_length + 2, literals);
+ // Zap the old map for the sake of the heap verifier.
+ if (Heap::ShouldZapGarbage()) ZapOptimizedCodeMap();
}
#ifdef DEBUG
- for (int i = 0; i < new_code_map->length(); i += kEntryLength) {
+ for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
ASSERT(new_code_map->get(i)->IsNativeContext());
ASSERT(new_code_map->get(i + 1)->IsCode());
ASSERT(Code::cast(new_code_map->get(i + 1))->kind() ==
@@ -9010,14 +9031,14 @@
ASSERT(new_code_map->get(i + 2)->IsFixedArray());
}
#endif
- shared->set_optimized_code_map(*new_code_map);
+ set_optimized_code_map(new_code_map);
+ return new_code_map;
}
void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
int index) {
- ASSERT(index > 0);
- ASSERT(optimized_code_map()->IsFixedArray());
+ ASSERT(index > kEntriesStart);
FixedArray* code_map = FixedArray::cast(optimized_code_map());
if (!bound()) {
FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
@@ -9031,15 +9052,18 @@
}
-void SharedFunctionInfo::ClearOptimizedCodeMap(const char* reason) {
- if (!optimized_code_map()->IsSmi()) {
- if (FLAG_trace_opt) {
- PrintF("[clearing entire optimizing code map (%s) for ", reason);
- ShortPrint();
- PrintF("]\n");
- }
- set_optimized_code_map(Smi::FromInt(0));
+void SharedFunctionInfo::ClearOptimizedCodeMap() {
+ FixedArray* code_map = FixedArray::cast(optimized_code_map());
+
+ // If the next map link slot is already used then the function was
+ // enqueued with code flushing and we remove it now.
+ if (!code_map->get(kNextMapIndex)->IsUndefined()) {
+ CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
+ flusher->EvictOptimizedCodeMap(this);
}
+
+ ASSERT(code_map->get(kNextMapIndex)->IsUndefined());
+ set_optimized_code_map(Smi::FromInt(0));
}
@@ -9050,11 +9074,11 @@
int i;
bool removed_entry = false;
FixedArray* code_map = FixedArray::cast(optimized_code_map());
- for (i = 0; i < code_map->length(); i += kEntryLength) {
+ for (i = kEntriesStart; i < code_map->length(); i += kEntryLength) {
ASSERT(code_map->get(i)->IsNativeContext());
if (Code::cast(code_map->get(i + 1)) == optimized_code) {
if (FLAG_trace_opt) {
- PrintF("[clearing optimizing code map (%s) for ", reason);
+ PrintF("[evicting entry from optimizing code map (%s) for ", reason);
ShortPrint();
PrintF("]\n");
}
@@ -9069,15 +9093,35 @@
i += kEntryLength;
}
if (removed_entry) {
- if (code_map->length() > kEntryLength) {
- RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, kEntryLength);
- } else {
- ClearOptimizedCodeMap(reason);
+ // Always trim even when array is cleared because of heap verifier.
+ RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, kEntryLength);
+ if (code_map->length() == kEntriesStart) {
+ ClearOptimizedCodeMap();
}
}
}
+void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
+ FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ ASSERT(shrink_by % kEntryLength == 0);
+ ASSERT(shrink_by <= code_map->length() - kEntriesStart);
+ // Always trim even when array is cleared because of heap verifier.
+ RightTrimFixedArray<FROM_GC>(GetHeap(), code_map, shrink_by);
+ if (code_map->length() == kEntriesStart) {
+ ClearOptimizedCodeMap();
+ }
+}
+
+
+void SharedFunctionInfo::ZapOptimizedCodeMap() {
+ FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ MemsetPointer(code_map->data_start(),
+ GetHeap()->the_hole_value(),
+ code_map->length());
+}
+
+
bool JSFunction::CompileLazy(Handle<JSFunction> function,
ClearExceptionFlag flag) {
bool result = true;
@@ -9717,7 +9761,7 @@
if (!value->IsSmi()) {
FixedArray* optimized_code_map = FixedArray::cast(value);
int length = optimized_code_map->length();
- for (int i = 0; i < length; i += 3) {
+ for (int i = kEntriesStart; i < length; i += kEntryLength) {
if (optimized_code_map->get(i) == native_context) {
return i + 1;
}
@@ -9808,9 +9852,10 @@
VisitExternalReferences(p, p + 1);
}
-byte Code::compare_nil_state() {
+byte Code::compare_nil_types() {
ASSERT(is_compare_nil_ic_stub());
- return CompareNilICStub::TypesFromExtraICState(extended_extra_ic_state());
+ return CompareNilICStub::ExtractTypesFromExtraICState(
+ extended_extra_ic_state());
}
@@ -13524,7 +13569,7 @@
// Ordering is irrelevant, since we are going to sort anyway.
SeededNumberDictionary* dict = element_dictionary();
if (IsJSArray() || dict->requires_slow_elements() ||
- dict->max_number_key() >= limit) {
+ dict->max_number_key() >= limit || map()->is_observed()) {
return PrepareSlowElementsForSort(limit);
}
// Convert to fast elements.
diff --git a/src/objects.h b/src/objects.h
index adb05cb..d466f65 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -851,7 +851,7 @@
// A template-ized version of the IsXXX functions.
-template <class C> static inline bool Is(Object* obj);
+template <class C> inline bool Is(Object* obj);
#ifdef VERIFY_HEAP
#define DECLARE_VERIFIER(Name) void Name##Verify();
@@ -4620,7 +4620,7 @@
inline void set_to_boolean_state(byte value);
// [compare_nil]: For kind COMPARE_NIL_IC tells what state the stub is in.
- byte compare_nil_state();
+ byte compare_nil_types();
// [has_function_cache]: For kind STUB tells whether there is a function
// cache is passed to the stub.
@@ -5807,7 +5807,7 @@
inline void ReplaceCode(Code* code);
// [optimized_code_map]: Map from native context to optimized code
- // and a shared literals array or Smi 0 if none.
+ // and a shared literals array or Smi(0) if none.
DECL_ACCESSORS(optimized_code_map, Object)
// Returns index i of the entry with the specified context. At position
@@ -5820,17 +5820,34 @@
void InstallFromOptimizedCodeMap(JSFunction* function, int index);
// Clear optimized code map.
- void ClearOptimizedCodeMap(const char* reason);
+ void ClearOptimizedCodeMap();
// Removed a specific optimized code object from the optimized code map.
void EvictFromOptimizedCodeMap(Code* optimized_code, const char* reason);
+ // Trims the optimized code map after entries have been removed.
+ void TrimOptimizedCodeMap(int shrink_by);
+
+ // Zaps the contents of backing optimized code map.
+ void ZapOptimizedCodeMap();
+
// Add a new entry to the optimized code map.
+ MUST_USE_RESULT MaybeObject* AddToOptimizedCodeMap(Context* native_context,
+ Code* code,
+ FixedArray* literals);
static void AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,
Handle<Context> native_context,
Handle<Code> code,
Handle<FixedArray> literals);
+
+ // Layout description of the optimized code map.
+ static const int kNextMapIndex = 0;
+ static const int kEntriesStart = 1;
static const int kEntryLength = 3;
+ static const int kFirstContextSlot = FixedArray::kHeaderSize + kPointerSize;
+ static const int kFirstCodeSlot = FixedArray::kHeaderSize + 2 * kPointerSize;
+ static const int kSecondEntryIndex = kEntryLength + kEntriesStart;
+ static const int kInitialLength = kEntriesStart + kEntryLength;
// [scope_info]: Scope info.
DECL_ACCESSORS(scope_info, ScopeInfo)
diff --git a/src/parser.cc b/src/parser.cc
index cff51bc..86a486f 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3113,7 +3113,12 @@
Expression* generator_object = factory()->NewVariableProxy(
current_function_state_->generator_object_variable());
Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
- return factory()->NewYield(generator_object, expression, kind, position);
+ Yield* yield =
+ factory()->NewYield(generator_object, expression, kind, position);
+ if (kind == Yield::DELEGATING) {
+ yield->set_index(current_function_state_->NextHandlerIndex());
+ }
+ return yield;
}
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 64dabf6..d6e8a37 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -55,7 +55,8 @@
resource_name_(resource_name),
line_number_(line_number),
shared_id_(0),
- security_token_id_(security_token_id) {
+ security_token_id_(security_token_id),
+ no_frame_ranges_(NULL) {
}
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index b1b163b..d923bc0 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -29,6 +29,7 @@
#include "profile-generator-inl.h"
+#include "compiler.h"
#include "global-handles.h"
#include "scopeinfo.h"
#include "unicode.h"
@@ -186,6 +187,11 @@
const char* const CodeEntry::kEmptyNamePrefix = "";
+CodeEntry::~CodeEntry() {
+ delete no_frame_ranges_;
+}
+
+
void CodeEntry::CopyData(const CodeEntry& source) {
tag_ = source.tag_;
name_prefix_ = source.name_prefix_;
@@ -531,13 +537,17 @@
}
-CodeEntry* CodeMap::FindEntry(Address addr) {
+CodeEntry* CodeMap::FindEntry(Address addr, Address* start) {
CodeTree::Locator locator;
if (tree_.FindGreatestLessThan(addr, &locator)) {
// locator.key() <= addr. Need to check that addr is within entry.
const CodeEntryInfo& entry = locator.value();
- if (addr < (locator.key() + entry.size))
+ if (addr < (locator.key() + entry.size)) {
+ if (start) {
+ *start = locator.key();
+ }
return entry.entry;
+ }
}
return NULL;
}
@@ -898,7 +908,26 @@
CodeEntry** entry = entries.start();
memset(entry, 0, entries.length() * sizeof(*entry));
if (sample.pc != NULL) {
- *entry++ = code_map_.FindEntry(sample.pc);
+ Address start;
+ CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start);
+ // If pc is in the function code before it set up stack frame or after the
+ // frame was destroyed SafeStackTraceFrameIterator incorrectly thinks that
+ // ebp contains return address of the current function and skips caller's
+ // frame. Check for this case and just skip such samples.
+ if (pc_entry) {
+ List<OffsetRange>* ranges = pc_entry->no_frame_ranges();
+ if (ranges) {
+ Code* code = Code::cast(HeapObject::FromAddress(start));
+ int pc_offset = static_cast<int>(sample.pc - code->instruction_start());
+ for (int i = 0; i < ranges->length(); i++) {
+ OffsetRange& range = ranges->at(i);
+ if (range.from <= pc_offset && pc_offset < range.to) {
+ return;
+ }
+ }
+ }
+ }
+ *entry++ = pc_entry;
if (sample.has_external_callback) {
// Don't use PC when in external callback code, as it can point
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 761291e..37cc57d 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -35,6 +35,8 @@
namespace v8 {
namespace internal {
+struct OffsetRange;
+
class TokenEnumerator {
public:
TokenEnumerator();
@@ -100,6 +102,7 @@
const char* resource_name,
int line_number,
int security_token_id));
+ ~CodeEntry();
INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
INLINE(const char* name_prefix() const) { return name_prefix_; }
@@ -112,6 +115,11 @@
INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
+ List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; }
+ void set_no_frame_ranges(List<OffsetRange>* ranges) {
+ no_frame_ranges_ = ranges;
+ }
+
void CopyData(const CodeEntry& source);
uint32_t GetCallUid() const;
bool IsSameAs(CodeEntry* entry) const;
@@ -126,6 +134,7 @@
int line_number_;
int shared_id_;
int security_token_id_;
+ List<OffsetRange>* no_frame_ranges_;
DISALLOW_COPY_AND_ASSIGN(CodeEntry);
};
@@ -251,7 +260,7 @@
CodeMap() : next_shared_id_(1) { }
void AddCode(Address addr, CodeEntry* entry, unsigned size);
void MoveCode(Address from, Address to);
- CodeEntry* FindEntry(Address addr);
+ CodeEntry* FindEntry(Address addr, Address* start = NULL);
int GetSharedId(Address addr);
void Print();
diff --git a/src/runtime.cc b/src/runtime.cc
index 1875588..849ddbf 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -676,7 +676,7 @@
array_buffer->set_backing_store(data);
Handle<Object> byte_length =
- isolate->factory()->NewNumber(static_cast<double>(allocated_length));
+ isolate->factory()->NewNumberFromSize(allocated_length);
CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
array_buffer->set_byte_length(*byte_length);
return true;
@@ -795,51 +795,41 @@
CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
ExternalArrayType arrayType;
- ElementsKind elementsKind;
size_t elementSize;
switch (arrayId) {
case ARRAY_ID_UINT8:
- elementsKind = EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
arrayType = kExternalUnsignedByteArray;
elementSize = 1;
break;
case ARRAY_ID_INT8:
- elementsKind = EXTERNAL_BYTE_ELEMENTS;
arrayType = kExternalByteArray;
elementSize = 1;
break;
case ARRAY_ID_UINT16:
- elementsKind = EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
arrayType = kExternalUnsignedShortArray;
elementSize = 2;
break;
case ARRAY_ID_INT16:
- elementsKind = EXTERNAL_SHORT_ELEMENTS;
arrayType = kExternalShortArray;
elementSize = 2;
break;
case ARRAY_ID_UINT32:
- elementsKind = EXTERNAL_UNSIGNED_INT_ELEMENTS;
arrayType = kExternalUnsignedIntArray;
elementSize = 4;
break;
case ARRAY_ID_INT32:
- elementsKind = EXTERNAL_INT_ELEMENTS;
arrayType = kExternalIntArray;
elementSize = 4;
break;
case ARRAY_ID_FLOAT32:
- elementsKind = EXTERNAL_FLOAT_ELEMENTS;
arrayType = kExternalFloatArray;
elementSize = 4;
break;
case ARRAY_ID_FLOAT64:
- elementsKind = EXTERNAL_DOUBLE_ELEMENTS;
arrayType = kExternalDoubleArray;
elementSize = 8;
break;
case ARRAY_ID_UINT8C:
- elementsKind = EXTERNAL_PIXEL_ELEMENTS;
arrayType = kExternalPixelArray;
elementSize = 1;
break;
@@ -857,16 +847,13 @@
ASSERT(byte_length % elementSize == 0);
size_t length = byte_length / elementSize;
- Handle<Object> length_obj =
- isolate->factory()->NewNumber(static_cast<double>(length));
+ Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
holder->set_length(*length_obj);
+
Handle<ExternalArray> elements =
isolate->factory()->NewExternalArray(
static_cast<int>(length), arrayType,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
- Handle<Map> map =
- isolate->factory()->GetElementsTransitionMap(holder, elementsKind);
- holder->set_map(*map);
holder->set_elements(*elements);
return isolate->heap()->undefined_value();
}
diff --git a/src/string-stream.h b/src/string-stream.h
index 0ba8f52..88b4afe 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -187,6 +187,31 @@
};
+// Utility class to print a list of items to a stream, divided by a separator.
+class SimpleListPrinter {
+ public:
+ explicit SimpleListPrinter(StringStream* stream, char separator = ',') {
+ separator_ = separator;
+ stream_ = stream;
+ first_ = true;
+ }
+
+ void Add(const char* str) {
+ if (first_) {
+ first_ = false;
+ } else {
+ stream_->Put(separator_);
+ }
+ stream_->Add(str);
+ }
+
+ private:
+ bool first_;
+ char separator_;
+ StringStream* stream_;
+};
+
+
} } // namespace v8::internal
#endif // V8_STRING_STREAM_H_
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index f43c9ac..89dee10 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -907,9 +907,8 @@
Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
- NilValue nil,
- CompareNilICStub::Types types) {
- CompareNilICStub stub(kNonStrictEquality, nil, types);
+ CompareNilICStub& stub) {
+ stub.SetKind(kNonStrictEquality);
Handle<String> name(isolate_->heap()->empty_string());
if (!receiver_map->is_shared()) {
diff --git a/src/stub-cache.h b/src/stub-cache.h
index cbaeace..9365d96 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -281,8 +281,7 @@
// ---
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
- NilValue nil,
- CompareNilICStub::Types types);
+ CompareNilICStub& stub);
// ---
diff --git a/src/type-info.cc b/src/type-info.cc
index 1757bee..21dcf74 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -192,13 +192,14 @@
Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- Map* first_map = code->FindFirstMap();
- ASSERT(first_map != NULL);
- return CanRetainOtherContext(first_map, *native_context_)
+ Handle<Map> first_map(code->FindFirstMap());
+ ASSERT(!first_map.is_null());
+ first_map = Map::CurrentMapForDeprecated(first_map);
+ return CanRetainOtherContext(*first_map, *native_context_)
? Handle<Map>::null()
- : Handle<Map>(first_map);
+ : first_map;
}
- return Handle<Map>::cast(map_or_code);
+ return Map::CurrentMapForDeprecated(Handle<Map>::cast(map_or_code));
}
@@ -208,13 +209,14 @@
Handle<Object> map_or_code = GetInfo(ast_id);
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- Map* first_map = code->FindFirstMap();
- ASSERT(first_map != NULL);
- return CanRetainOtherContext(first_map, *native_context_)
+ Handle<Map> first_map(code->FindFirstMap());
+ ASSERT(!first_map.is_null());
+ first_map = Map::CurrentMapForDeprecated(first_map);
+ return CanRetainOtherContext(*first_map, *native_context_)
? Handle<Map>::null()
- : Handle<Map>(first_map);
+ : first_map;
}
- return Handle<Map>::cast(map_or_code);
+ return Map::CurrentMapForDeprecated(Handle<Map>::cast(map_or_code));
}
@@ -223,7 +225,9 @@
Handle<Object> maybe_code = GetInfo(id);
if (maybe_code->IsCode()) {
Map* first_map = Handle<Code>::cast(maybe_code)->FindFirstMap();
- if (first_map != NULL) return Handle<Map>(first_map);
+ if (first_map != NULL) {
+ return Map::CurrentMapForDeprecated(Handle<Map>(first_map));
+ }
}
return Handle<Map>();
}
@@ -347,7 +351,8 @@
Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(
ObjectLiteral::Property* prop) {
ASSERT(ObjectLiteralStoreIsMonomorphic(prop));
- return Handle<Map>::cast(GetInfo(prop->key()->LiteralFeedbackId()));
+ return Map::CurrentMapForDeprecated(
+ Handle<Map>::cast(GetInfo(prop->key()->LiteralFeedbackId())));
}
@@ -426,11 +431,12 @@
if (state != CompareIC::KNOWN_OBJECT) {
return Handle<Map>::null();
}
- Map* first_map = code->FindFirstMap();
- ASSERT(first_map != NULL);
- return CanRetainOtherContext(first_map, *native_context_)
+ Handle<Map> first_map(code->FindFirstMap());
+ ASSERT(!first_map.is_null());
+ first_map = Map::CurrentMapForDeprecated(first_map);
+ return CanRetainOtherContext(*first_map, *native_context_)
? Handle<Map>::null()
- : Handle<Map>(first_map);
+ : first_map;
}
@@ -637,9 +643,9 @@
Handle<Object> object = GetInfo(id);
if (object->IsCode() &&
Handle<Code>::cast(object)->is_compare_nil_ic_stub()) {
- return Handle<Code>::cast(object)->compare_nil_state();
+ return Handle<Code>::cast(object)->compare_nil_types();
} else {
- return CompareNilICStub::kFullCompare;
+ return CompareNilICStub::Types::FullCompare().ToIntegral();
}
}
diff --git a/src/utils.h b/src/utils.h
index b2c2ff1..93cded1 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -242,42 +242,52 @@
// ----------------------------------------------------------------------------
// BitField is a help template for encoding and decode bitfield with
// unsigned content.
-template<class T, int shift, int size>
-class BitField {
+
+template<class T, int shift, int size, class U>
+class BitFieldBase {
public:
- // A uint32_t mask of bit field. To use all bits of a uint32 in a
- // bitfield without compiler warnings we have to compute 2^32 without
- // using a shift count of 32.
- static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
- static const uint32_t kShift = shift;
- static const uint32_t kSize = size;
+ // A type U mask of bit field. To use all bits of a type U of x bits
+ // in a bitfield without compiler warnings we have to compute 2^x
+ // without using a shift count of x in the computation.
+ static const U kOne = static_cast<U>(1U);
+ static const U kMask = ((kOne << shift) << size) - (kOne << shift);
+ static const U kShift = shift;
+ static const U kSize = size;
// Value for the field with all bits set.
static const T kMax = static_cast<T>((1U << size) - 1);
// Tells whether the provided value fits into the bit field.
static bool is_valid(T value) {
- return (static_cast<uint32_t>(value) & ~static_cast<uint32_t>(kMax)) == 0;
+ return (static_cast<U>(value) & ~static_cast<U>(kMax)) == 0;
}
- // Returns a uint32_t with the bit field value encoded.
- static uint32_t encode(T value) {
+ // Returns a type U with the bit field value encoded.
+ static U encode(T value) {
ASSERT(is_valid(value));
- return static_cast<uint32_t>(value) << shift;
+ return static_cast<U>(value) << shift;
}
- // Returns a uint32_t with the bit field value updated.
- static uint32_t update(uint32_t previous, T value) {
+ // Returns a type U with the bit field value updated.
+ static U update(U previous, T value) {
return (previous & ~kMask) | encode(value);
}
// Extracts the bit field from the value.
- static T decode(uint32_t value) {
+ static T decode(U value) {
return static_cast<T>((value & kMask) >> shift);
}
};
+template<class T, int shift, int size>
+class BitField : public BitFieldBase<T, shift, size, uint32_t> { };
+
+
+template<class T, int shift, int size>
+class BitField64 : public BitFieldBase<T, shift, size, uint64_t> { };
+
+
// ----------------------------------------------------------------------------
// Hash function.
@@ -1030,6 +1040,7 @@
void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
T ToIntegral() const { return bits_; }
bool operator==(const EnumSet& set) { return bits_ == set.bits_; }
+ bool operator!=(const EnumSet& set) { return bits_ != set.bits_; }
EnumSet<E, T> operator|(const EnumSet& set) const {
return EnumSet<E, T>(bits_ | set.bits_);
}
diff --git a/src/v8natives.js b/src/v8natives.js
index db92132..b2ea749 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -1767,7 +1767,9 @@
// If the formal parameters string include ) - an illegal
// character - it may make the combined function expression
// compile. We avoid this problem by checking for this early on.
- if (p.indexOf(')') != -1) throw MakeSyntaxError('paren_in_arg_string',[]);
+ if (%_CallFunction(p, ')', StringIndexOf) != -1) {
+ throw MakeSyntaxError('paren_in_arg_string',[]);
+ }
// If the formal parameters include an unbalanced block comment, the
// function must be rejected. Since JavaScript does not allow nested
// comments we can include a trailing block comment to catch this.
diff --git a/src/version.cc b/src/version.cc
index b759641..1428202 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 19
-#define BUILD_NUMBER 1
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 2
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index f7ded18..f87d952 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -287,8 +287,8 @@
// The optimized code map must never be empty, so check the first elements.
Label install_optimized;
// Speculatively move code object into edx.
- __ movq(rdx, FieldOperand(rbx, FixedArray::kHeaderSize + kPointerSize));
- __ cmpq(rcx, FieldOperand(rbx, FixedArray::kHeaderSize));
+ __ movq(rdx, FieldOperand(rbx, SharedFunctionInfo::kFirstCodeSlot));
+ __ cmpq(rcx, FieldOperand(rbx, SharedFunctionInfo::kFirstContextSlot));
__ j(equal, &install_optimized);
// Iterate through the rest of map backwards. rdx holds an index.
@@ -298,9 +298,9 @@
__ SmiToInteger32(rdx, rdx);
__ bind(&loop);
// Do not double check first entry.
- __ cmpq(rdx, Immediate(SharedFunctionInfo::kEntryLength));
+ __ cmpq(rdx, Immediate(SharedFunctionInfo::kSecondEntryIndex));
__ j(equal, &restore);
- __ subq(rdx, Immediate(SharedFunctionInfo::kEntryLength)); // Skip an entry.
+ __ subq(rdx, Immediate(SharedFunctionInfo::kEntryLength));
__ cmpq(rcx, FieldOperand(rbx,
rdx,
times_pointer_size,
@@ -1272,6 +1272,17 @@
}
+static void BinaryOpStub_GenerateRegisterArgsPushUnderReturn(
+ MacroAssembler* masm) {
+ // Push arguments, but ensure they are under the return address
+ // for a tail call.
+ __ pop(rcx);
+ __ push(rdx);
+ __ push(rax);
+ __ push(rcx);
+}
+
+
void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
ASSERT(op_ == Token::ADD);
Label left_not_string, call_runtime;
@@ -1284,8 +1295,9 @@
__ JumpIfSmi(left, &left_not_string, Label::kNear);
__ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
__ j(above_equal, &left_not_string, Label::kNear);
- StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
- GenerateRegisterArgsPush(masm);
+ StringAddStub string_add_left_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB));
+ BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
__ TailCallStub(&string_add_left_stub);
// Left operand is not a string, test right.
@@ -1294,8 +1306,9 @@
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
__ j(above_equal, &call_runtime, Label::kNear);
- StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
- GenerateRegisterArgsPush(masm);
+ StringAddStub string_add_right_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB));
+ BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
__ TailCallStub(&string_add_right_stub);
// Neither argument is a string.
@@ -1322,8 +1335,12 @@
if (call_runtime.is_linked()) {
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
}
@@ -1356,8 +1373,9 @@
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
__ j(above_equal, &call_runtime);
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
- GenerateRegisterArgsPush(masm);
+ StringAddStub string_add_stub((StringAddFlags)
+ (ERECT_FRAME | NO_STRING_CHECK_IN_STUB));
+ BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
__ TailCallStub(&string_add_stub);
__ bind(&call_runtime);
@@ -1442,8 +1460,12 @@
GenerateTypeTransition(masm);
__ bind(&gc_required);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -1462,8 +1484,12 @@
}
__ bind(&call_runtime);
- GenerateRegisterArgsPush(masm);
- GenerateCallRuntime(masm);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ GenerateCallRuntime(masm);
+ }
+ __ Ret();
}
@@ -1507,10 +1533,8 @@
void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
- __ pop(rcx);
__ push(rdx);
__ push(rax);
- __ push(rcx);
}
@@ -4791,7 +4815,7 @@
__ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right).
// Make sure that both arguments are strings if not known in advance.
- if (flags_ == NO_STRING_ADD_FLAGS) {
+ if ((flags_ & NO_STRING_ADD_FLAGS) != 0) {
__ JumpIfSmi(rax, &call_runtime);
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
__ j(above_equal, &call_runtime);
@@ -5068,15 +5092,53 @@
// Just jump to runtime to add the two strings.
__ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm, rcx);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ CallRuntime(Runtime::kStringAdd, 2);
+ }
+ __ Ret();
+ } else {
+ __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+ }
if (call_builtin.is_linked()) {
__ bind(&call_builtin);
- __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ if ((flags_ & ERECT_FRAME) != 0) {
+ GenerateRegisterArgsPop(masm, rcx);
+ // Build a frame
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(builtin_id, CALL_FUNCTION);
+ }
+ __ Ret();
+ } else {
+ __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ }
}
}
+void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+ __ push(rax);
+ __ push(rdx);
+}
+
+
+void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm,
+ Register temp) {
+ __ pop(temp);
+ __ pop(rdx);
+ __ pop(rax);
+ __ push(temp);
+}
+
+
void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
int stack_offset,
Register arg,
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index eafb960..f6cfad0 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -207,11 +207,13 @@
// Flag that indicates how to generate code for the stub StringAddStub.
enum StringAddFlags {
- NO_STRING_ADD_FLAGS = 0,
+ NO_STRING_ADD_FLAGS = 1 << 0,
// Omit left string check in stub (left is definitely a string).
- NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
+ NO_STRING_CHECK_LEFT_IN_STUB = 1 << 1,
// Omit right string check in stub (right is definitely a string).
- NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
+ NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 2,
+ // Stub needs a frame before calling the runtime
+ ERECT_FRAME = 1 << 3,
// Omit both string checks in stub.
NO_STRING_CHECK_IN_STUB =
NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
@@ -236,6 +238,9 @@
Register scratch3,
Label* slow);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
+
const StringAddFlags flags_;
};
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 0e2b49e..a579f52 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -267,7 +267,7 @@
if (FLAG_trace_osr) {
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => node=%u, frame=%d->%d]\n",
ast_id,
input_frame_size,
@@ -362,189 +362,12 @@
PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
ok ? "finished" : "aborted",
reinterpret_cast<intptr_t>(function_));
- function_->PrintName();
+ PrintFunctionName();
PrintF(" => pc=0x%0" V8PRIxPTR "]\n", output_[0]->GetPc());
}
}
-void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
- int frame_index) {
- BailoutId node_id = BailoutId(iterator->Next());
- JSFunction* function;
- if (frame_index != 0) {
- function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- } else {
- int closure_id = iterator->Next();
- USE(closure_id);
- ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
- function = function_;
- }
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating ");
- function->PrintName();
- PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
- }
-
- // The 'fixed' part of the frame consists of the incoming parameters and
- // the part described by JavaScriptFrameConstants.
- unsigned fixed_frame_size = ComputeFixedSize(function);
- unsigned input_frame_size = input_->GetFrameSize();
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
-
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
- ASSERT(frame_index >= 0 && frame_index < output_count_);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address for the bottommost output frame can be computed from
- // the input frame pointer and the output frame's height. For all
- // subsequent output frames, it can be computed from the previous one's
- // top address and the current frame's size.
- intptr_t top_address;
- if (is_bottommost) {
- // 2 = context and function in the frame.
- top_address =
- input_->GetRegister(rbp.code()) - (2 * kPointerSize) - height_in_bytes;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = function->shared()->formal_parameter_count() + 1;
- unsigned output_offset = output_frame_size;
- unsigned input_offset = input_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- input_offset -= (parameter_count * kPointerSize);
-
- // There are no translation commands for the caller's pc and fp, the
- // context, and the function. Synthesize their values and set them up
- // explicitly.
- //
- // The caller's pc for the bottommost output frame is the same as in the
- // input frame. For all subsequent output frames, it can be read from the
- // previous one. This frame's pc can be computed from the non-optimized
- // function code and AST id of the bailout.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- intptr_t value;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetPc();
- }
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; caller's pc\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The caller's frame pointer for the bottommost output frame is the same
- // as in the input frame. For all subsequent output frames, it can be
- // read from the previous one. Also compute and set this frame's frame
- // pointer.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = output_[frame_index - 1]->GetFp();
- }
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- ASSERT(!is_bottommost || input_->GetRegister(rbp.code()) == fp_value);
- output_frame->SetFp(fp_value);
- if (is_topmost) output_frame->SetRegister(rbp.code(), fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // For the bottommost output frame the context can be gotten from the input
- // frame. For all subsequent output frames it can be gotten from the function
- // so long as we don't inline functions that need local contexts.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- if (is_bottommost) {
- value = input_->GetFrameSlot(input_offset);
- } else {
- value = reinterpret_cast<intptr_t>(function->context());
- }
- output_frame->SetFrameSlot(output_offset, value);
- output_frame->SetContext(value);
- if (is_topmost) output_frame->SetRegister(rsi.code(), value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR "; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // The function was mentioned explicitly in the BEGIN_FRAME.
- output_offset -= kPointerSize;
- input_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(function);
- // The function for the bottommost output frame should also agree with the
- // input frame.
- ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR "; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Translate the rest of the frame.
- for (unsigned i = 0; i < height; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
- ASSERT(0 == output_offset);
-
- // Compute this frame's PC, state, and continuation.
- Code* non_optimized_code = function->shared()->code();
- FixedArray* raw_data = non_optimized_code->deoptimization_data();
- DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
- Address start = non_optimized_code->instruction_start();
- unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
- unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
- intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
- output_frame->SetPc(pc_value);
-
- FullCodeGenerator::State state =
- FullCodeGenerator::StateField::decode(pc_and_state);
- output_frame->SetState(Smi::FromInt(state));
-
- // Set the continuation for the topmost frame.
- if (is_topmost && bailout_type_ != DEBUGGER) {
- Builtins* builtins = isolate_->builtins();
- Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
- if (bailout_type_ == LAZY) {
- continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
- } else if (bailout_type_ == SOFT) {
- continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
- } else {
- ASSERT(bailout_type_ == EAGER);
- }
- output_frame->SetContinuation(
- reinterpret_cast<intptr_t>(continuation->entry()));
- }
-}
-
-
void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
// Set the register values. The values are not important as there are no
// callee saved registers in JavaScript frames, so all registers are
@@ -586,6 +409,12 @@
}
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+ // There is no dynamic alignment padding on x64 in the input frame.
+ return false;
+}
+
+
#define __ masm()->
void Deoptimizer::EntryGenerator::Generate() {
diff --git a/src/x64/frames-x64.cc b/src/x64/frames-x64.cc
index 1d6adfd..a811a34 100644
--- a/src/x64/frames-x64.cc
+++ b/src/x64/frames-x64.cc
@@ -43,6 +43,10 @@
}
+Register JavaScriptFrame::fp_register() { return rbp; }
+Register JavaScriptFrame::context_register() { return rsi; }
+
+
Register StubFailureTrampolineFrame::fp_register() { return rbp; }
Register StubFailureTrampolineFrame::context_register() { return rsi; }
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 19fa0aa..22c6fae 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -157,6 +157,7 @@
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.
__ push(rdi); // Callee's JS Function.
+ info->AddNoFrameRange(0, masm_->pc_offset());
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
@@ -406,6 +407,7 @@
// patch with the code required by the debugger.
__ movq(rsp, rbp);
__ pop(rbp);
+ int no_frame_start = masm_->pc_offset();
int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
__ Ret(arguments_bytes, rcx);
@@ -423,6 +425,7 @@
ASSERT(Assembler::kJSReturnSequenceLength <=
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
}
}
@@ -1946,8 +1949,96 @@
break;
}
- case Yield::DELEGATING:
- UNIMPLEMENTED();
+ case Yield::DELEGATING: {
+ VisitForStackValue(expr->generator_object());
+
+ // Initial stack layout is as follows:
+ // [sp + 1 * kPointerSize] iter
+ // [sp + 0 * kPointerSize] g
+
+ Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+ // Initial send value is undefined.
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ jmp(&l_send);
+
+ // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
+ __ bind(&l_catch);
+ handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+ __ movq(rcx, Operand(rsp, 1 * kPointerSize)); // iter
+ __ push(rcx); // iter
+ __ push(rax); // exception
+ __ movq(rax, rcx); // iter
+ __ LoadRoot(rcx, Heap::kthrow_stringRootIndex); // "throw"
+ Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(throw_ic); // iter.throw in rax
+ __ jmp(&l_call);
+
+ // try { received = yield result.value }
+ __ bind(&l_try);
+ __ pop(rax); // result.value
+ __ PushTryHandler(StackHandler::CATCH, expr->index());
+ const int handler_size = StackHandlerConstants::kSize;
+ __ push(rax); // result.value
+ __ push(Operand(rsp, (0 + 1) * kPointerSize + handler_size)); // g
+ __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+ __ movq(context_register(),
+ Operand(rbp, StandardFrameConstants::kContextOffset));
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &l_resume);
+ EmitReturnIteratorResult(false);
+ __ bind(&l_resume); // received in rax
+ __ PopTryHandler();
+
+ // receiver = iter; f = iter.send; arg = received;
+ __ bind(&l_send);
+ __ movq(rcx, Operand(rsp, 1 * kPointerSize)); // iter
+ __ push(rcx); // iter
+ __ push(rax); // received
+ __ movq(rax, rcx); // iter
+ __ LoadRoot(rcx, Heap::ksend_stringRootIndex); // "send"
+ Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(send_ic); // iter.send in rax
+
+ // result = f.call(receiver, arg);
+ __ bind(&l_call);
+ Label l_call_runtime;
+ __ JumpIfSmi(rax, &l_call_runtime);
+ __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
+ __ j(not_equal, &l_call_runtime);
+ __ movq(rdi, rax);
+ ParameterCount count(1);
+ __ InvokeFunction(rdi, count, CALL_FUNCTION,
+ NullCallWrapper(), CALL_AS_METHOD);
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ __ jmp(&l_loop);
+ __ bind(&l_call_runtime);
+ __ push(rax);
+ __ CallRuntime(Runtime::kCall, 3);
+
+ // val = result.value; if (!result.done) goto l_try;
+ __ bind(&l_loop);
+ // result.value
+ __ push(rax); // save result
+ __ LoadRoot(rcx, Heap::kvalue_stringRootIndex); // "value"
+ Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(value_ic); // result.value in rax
+ __ pop(rbx); // result
+ __ push(rax); // result.value
+ __ movq(rax, rbx); // result
+ __ LoadRoot(rcx, Heap::kdone_stringRootIndex); // "done"
+ Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(done_ic); // result.done in rax
+ ToBooleanStub stub(rax);
+ __ push(rax);
+ __ CallStub(&stub);
+ __ testq(rax, rax);
+ __ j(zero, &l_try);
+
+ // result.value
+ __ pop(rax); // result.value
+ context()->DropAndPlug(2, rax); // drop iter and g
+ break;
+ }
}
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index cc48382..9a1ce98 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -174,6 +174,7 @@
} else {
__ push(rdi); // Callee's JS function.
}
+ info()->AddNoFrameRange(0, masm_->pc_offset());
}
// Reserve space for the stack slots needed by the code.
@@ -1862,6 +1863,11 @@
}
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
+ __ int3();
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -2084,46 +2090,6 @@
}
-void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
- Register reg = ToRegister(instr->value());
- int false_block = chunk_->LookupDestination(instr->false_block_id());
-
- // If the expression is known to be untagged or a smi, then it's definitely
- // not null, and it can't be a an undetectable object.
- if (instr->hydrogen()->representation().IsSpecialization() ||
- instr->hydrogen()->type().IsSmi()) {
- EmitGoto(false_block);
- return;
- }
-
- int true_block = chunk_->LookupDestination(instr->true_block_id());
- Heap::RootListIndex nil_value = instr->nil() == kNullValue ?
- Heap::kNullValueRootIndex :
- Heap::kUndefinedValueRootIndex;
- __ CompareRoot(reg, nil_value);
- if (instr->kind() == kStrictEquality) {
- EmitBranch(true_block, false_block, equal);
- } else {
- Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ?
- Heap::kUndefinedValueRootIndex :
- Heap::kNullValueRootIndex;
- Label* true_label = chunk_->GetAssemblyLabel(true_block);
- Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ j(equal, true_label);
- __ CompareRoot(reg, other_nil_value);
- __ j(equal, true_label);
- __ JumpIfSmi(reg, false_label);
- // Check for undetectable objects by looking in the bit field in
- // the map. The object has already been smi checked.
- Register scratch = ToRegister(instr->temp());
- __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
- __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- EmitBranch(true_block, false_block, not_zero);
- }
-}
-
-
Condition LCodeGen::EmitIsObject(Register input,
Label* is_not_object,
Label* is_object) {
@@ -2561,9 +2527,11 @@
count++;
}
}
+ int no_frame_start = -1;
if (NeedsEagerFrame()) {
__ movq(rsp, rbp);
__ pop(rbp);
+ no_frame_start = masm_->pc_offset();
}
if (instr->has_constant_parameter_count()) {
__ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
@@ -2578,6 +2546,9 @@
__ addq(rsp, reg);
__ jmp(return_addr_reg);
}
+ if (no_frame_start != -1) {
+ info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+ }
}
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index c89efd9..1217a40 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -219,15 +219,6 @@
}
-void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
- stream->Add("if ");
- value()->PrintTo(stream);
- stream->Add(kind() == kStrictEquality ? " === " : " == ");
- stream->Add(nil() == kNullValue ? "null" : "undefined");
- stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
-}
-
-
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if is_object(");
value()->PrintTo(stream);
@@ -976,6 +967,11 @@
}
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+ return new(zone()) LDebugBreak();
+}
+
+
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
if (value->EmitAtUses()) {
@@ -1641,13 +1637,6 @@
}
-LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
- ASSERT(instr->value()->representation().IsTagged());
- LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
- return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
-}
-
-
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 7de1a7d..747d8e7 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -89,6 +89,7 @@
V(ConstantI) \
V(ConstantT) \
V(Context) \
+ V(DebugBreak) \
V(DeclareGlobals) \
V(DeleteProperty) \
V(Deoptimize) \
@@ -114,7 +115,6 @@
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
- V(IsNilAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
@@ -822,26 +822,6 @@
};
-class LIsNilAndBranch: public LControlInstruction<1, 1> {
- public:
- LIsNilAndBranch(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
- temps_[0] = temp;
- }
-
- LOperand* value() { return inputs_[0]; }
- LOperand* temp() { return temps_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch)
-
- EqualityKind kind() const { return hydrogen()->kind(); }
- NilValue nil() const { return hydrogen()->nil(); }
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LIsObjectAndBranch: public LControlInstruction<1, 0> {
public:
explicit LIsObjectAndBranch(LOperand* value) {
@@ -1193,6 +1173,12 @@
};
+class LDebugBreak: public LTemplateInstruction<0, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCmpMapAndBranch(LOperand* value) {
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index ecffeaa..0a91ed5 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -53,6 +53,7 @@
'test-bignum.cc',
'test-bignum-dtoa.cc',
'test-circular-queue.cc',
+ 'test-compare-nil-ic-stub.cc',
'test-compiler.cc',
'test-conversions.cc',
'test-cpu-profiler.cc',
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index e5523b2..91c6d70 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -39,8 +39,9 @@
# when snapshot is on, so I am marking it PASS || FAIL
test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
-# BUG(2628): This test is flaky and sometimes fails, but should not crash.
+# BUG(2628): These tests are flaky and sometimes fail, but should not crash.
test-cpu-profiler/CollectCpuProfile: PASS || FAIL
+test-cpu-profiler/SampleWhenFrameIsNotSetup: PASS || FAIL
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
@@ -81,6 +82,14 @@
test-serialize/DeserializeFromSecondSerialization: SKIP
##############################################################################
+[ $arch == arm || $arch == mipsel ]
+
+# BUG(2628): Signal may come when pc is close to frame enter/exit code and on
+# simulator the stack frame is not set up when it is expected to be for the pc
+# value.
+test-cpu-profiler/SampleWhenFrameIsNotSetup: SKIP
+
+##############################################################################
[ $arch == android_arm || $arch == android_ia32 ]
# Tests crash as there is no /tmp directory in Android.
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 4fccce6..2093dbb 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -15883,9 +15883,12 @@
}
+// We need at least 165kB for an x64 debug build with clang and ASAN.
+static const int stack_breathing_room = 256 * i::KB;
+
+
TEST(SetResourceConstraints) {
- static const int K = 1024;
- uint32_t* set_limit = ComputeStackLimit(128 * K);
+ uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
// Set stack limit.
v8::ResourceConstraints constraints;
@@ -15909,8 +15912,7 @@
uint32_t* set_limit;
{
v8::Locker locker(CcTest::default_isolate());
- static const int K = 1024;
- set_limit = ComputeStackLimit(128 * K);
+ set_limit = ComputeStackLimit(stack_breathing_room);
// Set stack limit.
v8::ResourceConstraints constraints;
diff --git a/test/cctest/test-compare-nil-ic-stub.cc b/test/cctest/test-compare-nil-ic-stub.cc
new file mode 100644
index 0000000..6177fde
--- /dev/null
+++ b/test/cctest/test-compare-nil-ic-stub.cc
@@ -0,0 +1,86 @@
+// Copyright 2006-2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "cctest.h"
+#include "code-stubs.h"
+
+
+using namespace v8::internal;
+
+#define Types CompareNilICStub::Types
+
+TEST(TypeConstructors) {
+ Types types;
+ types.Add(CompareNilICStub::MONOMORPHIC_MAP);
+ Types types2(types);
+ CHECK_EQ(types.ToIntegral(), types2.ToIntegral());
+}
+
+TEST(ExternalICStateParsing) {
+ Types types;
+ types.Add(CompareNilICStub::UNDEFINED);
+ CompareNilICStub stub(kNonStrictEquality, kUndefinedValue, types);
+ CompareNilICStub stub2(stub.GetExtraICState());
+ CHECK_EQ(stub.GetKind(), stub2.GetKind());
+ CHECK_EQ(stub.GetNilValue(), stub2.GetNilValue());
+ CHECK_EQ(stub.GetTypes().ToIntegral(), stub2.GetTypes().ToIntegral());
+}
+
+TEST(SettingTypes) {
+ Types state;
+ CHECK(state.IsEmpty());
+ state.Add(CompareNilICStub::NULL_TYPE);
+ CHECK(!state.IsEmpty());
+ CHECK(state.Contains(CompareNilICStub::NULL_TYPE));
+ CHECK(!state.Contains(CompareNilICStub::UNDEFINED));
+ CHECK(!state.Contains(CompareNilICStub::UNDETECTABLE));
+ state.Add(CompareNilICStub::UNDEFINED);
+ CHECK(state.Contains(CompareNilICStub::UNDEFINED));
+ CHECK(state.Contains(CompareNilICStub::NULL_TYPE));
+ CHECK(!state.Contains(CompareNilICStub::UNDETECTABLE));
+}
+
+TEST(ClearTypes) {
+ Types state;
+ state.Add(CompareNilICStub::NULL_TYPE);
+ state.RemoveAll();
+ CHECK(state.IsEmpty());
+}
+
+TEST(FullCompare) {
+ Types state;
+ CHECK(Types::FullCompare() != state);
+ state.Add(CompareNilICStub::UNDEFINED);
+ CHECK(state != Types::FullCompare());
+ state.Add(CompareNilICStub::NULL_TYPE);
+ CHECK(state != Types::FullCompare());
+ state.Add(CompareNilICStub::UNDETECTABLE);
+ CHECK(state == Types::FullCompare());
+}
diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc
index 651dc59..cf2092e 100644
--- a/test/cctest/test-conversions.cc
+++ b/test/cctest/test-conversions.cc
@@ -249,6 +249,7 @@
CHECK_EQ(1e-106, StringToDouble(&uc, ".000001e-100", NO_FLAGS));
}
+
class OneBit1: public BitField<uint32_t, 0, 1> {};
class OneBit2: public BitField<uint32_t, 7, 1> {};
class EightBit1: public BitField<uint32_t, 0, 8> {};
@@ -286,3 +287,21 @@
CHECK(!EightBit1::is_valid(256));
CHECK(!EightBit2::is_valid(256));
}
+
+
+class UpperBits: public BitField64<int, 61, 3> {};
+class MiddleBits: public BitField64<int, 31, 2> {};
+
+TEST(BitField64) {
+ uint64_t x;
+
+ // Test most significant bits.
+ x = V8_2PART_UINT64_C(0xE0000000, 00000000);
+ CHECK(x == UpperBits::encode(7));
+ CHECK_EQ(7, UpperBits::decode(x));
+
+ // Test the 32/64-bit boundary bits.
+ x = V8_2PART_UINT64_C(0x00000001, 80000000);
+ CHECK(x == MiddleBits::encode(3));
+ CHECK_EQ(3, MiddleBits::decode(x));
+}
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index d73be18..56aa9a7 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -122,7 +122,8 @@
0,
ToAddress(0x1000),
0x100,
- ToAddress(0x10000));
+ ToAddress(0x10000),
+ NULL);
processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
"bbb",
ToAddress(0x1200),
@@ -549,3 +550,72 @@
cpu_profiler->DeleteAllCpuProfiles();
}
+
+
+
+static const char* cpu_profiler_test_source2 = "function loop() {}\n"
+"function delay() { loop(); }\n"
+"function start(count) {\n"
+" var k = 0;\n"
+" do {\n"
+" delay();\n"
+" } while (++k < count*100*1000);\n"
+"}\n";
+
+// Check that the profile tree doesn't contain unexpecte traces:
+// - 'loop' can be called only by 'delay'
+// - 'delay' may be called only by 'start'
+// The profile will look like the following:
+//
+// [Top down]:
+// 135 0 (root) [-1] #1
+// 121 72 start [-1] #3
+// 49 33 delay [-1] #4
+// 16 16 loop [-1] #5
+// 14 14 (program) [-1] #2
+TEST(SampleWhenFrameIsNotSetup) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+
+ v8::Script::Compile(v8::String::New(cpu_profiler_test_source2))->Run();
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(v8::String::New("start")));
+
+ v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+ v8::Local<v8::String> profile_name = v8::String::New("my_profile");
+
+ cpu_profiler->StartCpuProfiling(profile_name);
+ int32_t repeat_count = 100;
+#if defined(USE_SIMULATOR)
+ // Simulators are much slower.
+ repeat_count = 1;
+#endif
+ v8::Handle<v8::Value> args[] = { v8::Integer::New(repeat_count) };
+ function->Call(env->Global(), ARRAY_SIZE(args), args);
+ const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
+
+ CHECK_NE(NULL, profile);
+ // Dump collected profile to have a better diagnostic in case of failure.
+ reinterpret_cast<i::CpuProfile*>(
+ const_cast<v8::CpuProfile*>(profile))->Print();
+
+ const v8::CpuProfileNode* root = profile->GetTopDownRoot();
+
+ ScopedVector<v8::Handle<v8::String> > names(3);
+ names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
+ names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
+ names[2] = v8::String::New("start");
+ CheckChildrenNames(root, names);
+
+ const v8::CpuProfileNode* startNode = FindChild(root, "start");
+ if (startNode->GetChildrenCount() > 0) {
+ CHECK_EQ(1, startNode->GetChildrenCount());
+ const v8::CpuProfileNode* delayNode = FindChild(startNode, "delay");
+ if (delayNode->GetChildrenCount() > 0) {
+ CHECK_EQ(1, delayNode->GetChildrenCount());
+ FindChild(delayNode, "loop");
+ }
+ }
+
+ cpu_profiler->DeleteAllCpuProfiles();
+}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 6473035..ca173c2 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -2814,7 +2814,6 @@
CcTest::InitializeVM();
Isolate* isolate = Isolate::Current();
- // Force experimental natives to compile to normalize heap layout.
Heap* heap = isolate->heap();
HandleScope scope(isolate);
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 2cb4646..dc21ac2 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -467,10 +467,17 @@
}
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define V8_WITH_ASAN 1
+#endif
+#endif
+
+
// Here is a memory use test that uses /proc, and is therefore Linux-only. We
// do not care how much memory the simulator uses, since it is only there for
-// debugging purposes.
-#if defined(__linux__) && !defined(USE_SIMULATOR)
+// debugging purposes. Testing with ASAN doesn't make sense, either.
+#if defined(__linux__) && !defined(USE_SIMULATOR) && !defined(V8_WITH_ASAN)
static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) {
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 05fea0b..170ec76 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -388,8 +388,7 @@
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
size_t kProgramSize = 1024 * 1024;
- i::SmartArrayPointer<char> program(
- reinterpret_cast<char*>(malloc(kProgramSize + 1)));
+ i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
memset(*program, '(', kProgramSize);
program[kProgramSize] = '\0';
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js
index 5c7ae13..d718993 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -28,10 +28,6 @@
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
// Flags: --track-allocation-sites --noalways-opt
-// TODO(mvstanton): remove --nooptimize-constructed-arrays and enable
-// the constructed array code below when the feature is turned on
-// by default.
-
// Test element kind of objects.
// Since --smi-only-arrays affects builtins, its default setting at compile
// time sticks if built with snapshot. If --smi-only-arrays is deactivated
diff --git a/test/mjsunit/compiler/dead-code.js b/test/mjsunit/compiler/dead-code.js
new file mode 100644
index 0000000..8b5bd2c
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code.js
@@ -0,0 +1,79 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function dead1(a, b) {
+ var x = a + b;
+ return a; // x is dead
+}
+
+function dead2(a, b) {
+ var x = a | 0;
+ var y = b | 0;
+ return a; // x and y are both dead
+}
+
+function dead3(a, b) {
+ var z;
+ if(a == 2) z = a;
+ else z = b;
+ return a; // z is dead
+}
+
+function dead4(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z++;
+ }
+ return a; // z is dead
+}
+
+function dead5(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z++;
+ }
+ var w = z + a;
+ return a; // z is dead
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead2(33, 32) == 33);
+assertTrue(dead3(33, 32) == 33);
+assertTrue(dead4(33) == 33);
+assertTrue(dead5(33) == 33);
+
+assertTrue(dead1(34, 7) == 34);
+assertTrue(dead2(34, 7) == 34);
+assertTrue(dead3(34, 7) == 34);
+assertTrue(dead4(34) == 34);
+assertTrue(dead5(34) == 34);
+
+assertTrue(dead1(3.4, 0.1) == 3.4);
+assertTrue(dead2(3.4, 0.1) == 3.4);
+assertTrue(dead3(3.4, 0.1) == 3.4);
+assertTrue(dead4(3.4) == 3.4);
+assertTrue(dead5(3.4) == 3.4);
diff --git a/test/mjsunit/compiler/dead-code2.js b/test/mjsunit/compiler/dead-code2.js
new file mode 100644
index 0000000..b058020
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code2.js
@@ -0,0 +1,84 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function dead1(a, b) {
+ { var x = a + b; }
+ return a; // x is dead
+}
+
+function dead2(a, b) {
+ { var x = a | 0; var y = b | 0; }
+ return a; // x and y are both dead
+}
+
+function dead3(a, b) {
+ {
+ var z;
+ if(a == 2) z = a;
+ else z = b;
+ }
+ return a; // z is dead
+}
+
+function dead4(a) {
+ {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z++;
+ }
+ }
+ return a; // z is dead
+}
+
+function dead5(a) {
+ {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z++;
+ }
+ var w = z + a;
+ }
+ return a; // z and w are dead
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead2(33, 32) == 33);
+assertTrue(dead3(33, 32) == 33);
+assertTrue(dead4(33) == 33);
+assertTrue(dead5(33) == 33);
+
+assertTrue(dead1(34, 7) == 34);
+assertTrue(dead2(34, 7) == 34);
+assertTrue(dead3(34, 7) == 34);
+assertTrue(dead4(34) == 34);
+assertTrue(dead5(34) == 34);
+
+assertTrue(dead1(3.4, 0.1) == 3.4);
+assertTrue(dead2(3.4, 0.1) == 3.4);
+assertTrue(dead3(3.4, 0.1) == 3.4);
+assertTrue(dead4(3.4) == 3.4);
+assertTrue(dead5(3.4) == 3.4);
diff --git a/test/mjsunit/compiler/dead-code3.js b/test/mjsunit/compiler/dead-code3.js
new file mode 100644
index 0000000..d057978
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code3.js
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function dead1(a, b) {
+ a + b; // dead
+ return a;
+}
+
+function dead2(a, b) {
+ a | 0; // dead
+ b | 0; // dead
+ return a; // x and y are both dead
+}
+
+function dead3(a, b) {
+ a == 2 ? a : b; // dead
+ return a;
+}
+
+function dead4(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z + 3; // dead
+ }
+ return a;
+}
+
+function dead5(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z + 3; // dead
+ z++;
+ }
+ var w = z + a;
+ return a; // z is dead
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead2(33, 32) == 33);
+assertTrue(dead3(33, 32) == 33);
+assertTrue(dead4(33) == 33);
+assertTrue(dead5(33) == 33);
+
+assertTrue(dead1(34, 7) == 34);
+assertTrue(dead2(34, 7) == 34);
+assertTrue(dead3(34, 7) == 34);
+assertTrue(dead4(34) == 34);
+assertTrue(dead5(34) == 34);
+
+assertTrue(dead1(3.4, 0.1) == 3.4);
+assertTrue(dead2(3.4, 0.1) == 3.4);
+assertTrue(dead3(3.4, 0.1) == 3.4);
+assertTrue(dead4(3.4) == 3.4);
+assertTrue(dead5(3.4) == 3.4);
diff --git a/test/mjsunit/compiler/dead-code4.js b/test/mjsunit/compiler/dead-code4.js
new file mode 100644
index 0000000..a5c20f8
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code4.js
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function dead1(a, b) {
+ (a | 0) + (b | 0); // dead
+ return a;
+}
+
+function dead2(a, b) {
+ a | 0; // dead
+ b | 0; // dead
+ return a; // x and y are both dead
+}
+
+function dead3(a, b) {
+ a == 2 ? (a | 0) : (b | 0); // dead
+ return a;
+}
+
+function dead4(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ (z | 0) + 3; // dead
+ }
+ return a;
+}
+
+function dead5(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ (z | 0) + 3; // dead
+ z++;
+ }
+ var w = z + a;
+ return a; // z is dead
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead2(33, 32) == 33);
+assertTrue(dead3(33, 32) == 33);
+assertTrue(dead4(33) == 33);
+assertTrue(dead5(33) == 33);
+
+assertTrue(dead1(34, 7) == 34);
+assertTrue(dead2(34, 7) == 34);
+assertTrue(dead3(34, 7) == 34);
+assertTrue(dead4(34) == 34);
+assertTrue(dead5(34) == 34);
+
+assertTrue(dead1(3.4, 0.1) == 3.4);
+assertTrue(dead2(3.4, 0.1) == 3.4);
+assertTrue(dead3(3.4, 0.1) == 3.4);
+assertTrue(dead4(3.4) == 3.4);
+assertTrue(dead5(3.4) == 3.4);
diff --git a/test/mjsunit/compiler/dead-code5.js b/test/mjsunit/compiler/dead-code5.js
new file mode 100644
index 0000000..834fa24
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code5.js
@@ -0,0 +1,89 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function dead1(a, b) {
+ a * b;
+ a << b;
+ a >> b;
+ a >>> b;
+ a | b;
+ a & b;
+ a ^ b;
+ return a;
+}
+
+function dead2(a, b) {
+ (a | 0) * b;
+ (a | 0) << b;
+ (a | 0) >> b;
+ (a | 0) >>> b;
+ (a | 0) | b;
+ (a | 0) & b;
+ (a | 0) ^ b;
+ return a;
+}
+
+function dead3(a, b) {
+ a == 2 ? (a * b) : (b * a); // dead
+ return a;
+}
+
+function dead4(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z * 3; // dead
+ }
+ return a;
+}
+
+function dead5(a) {
+ var z = 3;
+ for (i = 0; i < 3; i++) {
+ z * 3; // dead
+ z++;
+ }
+ var w = z * a;
+ return a; // w is dead
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead2(33, 32) == 33);
+assertTrue(dead3(33, 32) == 33);
+assertTrue(dead4(33) == 33);
+assertTrue(dead5(33) == 33);
+
+assertTrue(dead1(34, 7) == 34);
+assertTrue(dead2(34, 7) == 34);
+assertTrue(dead3(34, 7) == 34);
+assertTrue(dead4(34) == 34);
+assertTrue(dead5(34) == 34);
+
+assertTrue(dead1(3.4, 0.1) == 3.4);
+assertTrue(dead2(3.4, 0.1) == 3.4);
+assertTrue(dead3(3.4, 0.1) == 3.4);
+assertTrue(dead4(3.4) == 3.4);
+assertTrue(dead5(3.4) == 3.4);
diff --git a/test/mjsunit/compiler/dead-code6.js b/test/mjsunit/compiler/dead-code6.js
new file mode 100644
index 0000000..ec9b843
--- /dev/null
+++ b/test/mjsunit/compiler/dead-code6.js
@@ -0,0 +1,73 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+// Test some dead code elimination scenarios
+
+function dead1(x, y) {
+ var a = x | 0, b = y | 0;
+ a * b;
+ a << b;
+ a >> b;
+ a >>> b;
+ a | b;
+ a & b;
+ a ^ b;
+ return x;
+}
+
+function dead2(x, y) {
+ var a = x | 0, b = y | 0;
+ (a | 0) * b;
+ (a | 0) << b;
+ (a | 0) >> b;
+ (a | 0) >>> b;
+ (a | 0) | b;
+ (a | 0) & b;
+ (a | 0) ^ b;
+ return x;
+}
+
+function dead3(a, b) {
+ a == 2 ? (a * b) : (b * a); // dead
+ return a;
+}
+
+assertTrue(dead1(33, 32) == 33);
+assertTrue(dead1(33, 32) == 33);
+%OptimizeFunctionOnNextCall(dead1);
+assertTrue(dead1(33, 32) == 33);
+
+assertTrue(dead2(34, 11) == 34);
+assertTrue(dead2(34, 11) == 34);
+%OptimizeFunctionOnNextCall(dead2);
+assertTrue(dead2(34, 11) == 34);
+
+assertTrue(dead3(35, 12) == 35);
+assertTrue(dead3(35, 12) == 35);
+%OptimizeFunctionOnNextCall(dead3);
+assertTrue(dead3(35, 12) == 35);
diff --git a/test/mjsunit/generated-transition-stub.js b/test/mjsunit/generated-transition-stub.js
index dd1043b..072ce9c 100644
--- a/test/mjsunit/generated-transition-stub.js
+++ b/test/mjsunit/generated-transition-stub.js
@@ -68,7 +68,7 @@
for (i = 0; i < 0x40000; ++i) {
a5[i] = 0;
}
- assertTrue(%HasFastSmiElements(a5));
+ assertTrue(%HasFastSmiElements(a5) || %HasFastDoubleElements(a5));
transition1(a5, 0, 2.5);
assertEquals(2.5, a5[0]);
}
diff --git a/test/mjsunit/harmony/generators-iteration.js b/test/mjsunit/harmony/generators-iteration.js
index d120ac7..e717f1b 100644
--- a/test/mjsunit/harmony/generators-iteration.js
+++ b/test/mjsunit/harmony/generators-iteration.js
@@ -86,6 +86,10 @@
testSend(g);
testThrow(g);
+ testNext(function*() { return yield* g(); });
+ testSend(function*() { return yield* g(); });
+ testThrow(function*() { return yield* g(); });
+
if (g instanceof GeneratorFunction) {
testNext(function() { return new g(); });
testSend(function() { return new g(); });
@@ -320,125 +324,158 @@
"foo",
[2, "1foo3", 5, "4foo6", "foofoo"]);
-function TestTryCatch() {
+function TestTryCatch(instantiate) {
function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; }
function Sentinel() {}
- var iter;
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test1(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test1(instantiate(g));
- iter = g();
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test2(iter) {
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test2(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test3(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test3(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test4(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test4(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertIteratorResult(3, false, iter.next());
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test5(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertIteratorResult(3, false, iter.next());
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ }
+ Test5(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test6(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test6(instantiate(g));
+
+ function Test7(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test7(instantiate(g));
}
-TestTryCatch();
+TestTryCatch(function (g) { return g(); });
+TestTryCatch(function* (g) { return yield* g(); });
-function TestTryFinally() {
+function TestTryFinally(instantiate) {
function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; }
function Sentinel() {}
function Sentinel2() {}
- var iter;
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test1(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test1(instantiate(g));
- iter = g();
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test2(iter) {
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test2(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test3(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test3(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.throw(new Sentinel));
- assertThrows(function() { iter.next(); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test4(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.throw(new Sentinel));
+ assertThrows(function() { iter.next(); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.throw(new Sentinel));
- assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
- assertThrows(function() { iter.next(); }, Error);
+ }
+ Test4(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test5(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.throw(new Sentinel));
+ assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test5(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.next());
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test6(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test6(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test7(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.next());
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test7(instantiate(g));
+
+ function Test8(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+
+ }
+ Test8(instantiate(g));
}
-TestTryFinally();
+TestTryFinally(function (g) { return g(); });
+TestTryFinally(function* (g) { return yield* g(); });
-function TestNestedTry() {
+function TestNestedTry(instantiate) {
function* g() {
try {
yield 1;
@@ -451,66 +488,82 @@
}
function Sentinel() {}
function Sentinel2() {}
- var iter;
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.next());
- assertIteratorResult(5, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test1(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.next());
+ assertIteratorResult(5, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test1(instantiate(g));
- iter = g();
- assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test2(iter) {
+ assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test2(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(4, false, iter.throw(new Sentinel));
- assertThrows(function() { iter.next(); }, Sentinel);
- assertThrows(function() { iter.next(); }, Error);
+ function Test3(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(4, false, iter.throw(new Sentinel));
+ assertThrows(function() { iter.next(); }, Sentinel);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test3(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(4, false, iter.throw(new Sentinel));
- assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
- assertThrows(function() { iter.next(); }, Error);
+ function Test4(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(4, false, iter.throw(new Sentinel));
+ assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test4(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.next());
- assertIteratorResult(5, false, iter.next());
- assertIteratorResult(undefined, true, iter.next());
- assertThrows(function() { iter.next(); }, Error);
+ function Test5(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.next());
+ assertIteratorResult(5, false, iter.next());
+ assertIteratorResult(undefined, true, iter.next());
+ assertThrows(function() { iter.next(); }, Error);
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertIteratorResult(4, false, iter.throw(new Sentinel2));
- assertThrows(function() { iter.next(); }, Sentinel2);
- assertThrows(function() { iter.next(); }, Error);
+ }
+ Test5(instantiate(g));
- iter = g();
- assertIteratorResult(1, false, iter.next());
- assertIteratorResult(2, false, iter.next());
- var exn = new Sentinel;
- assertIteratorResult(exn, false, iter.throw(exn));
- assertIteratorResult(3, false, iter.next());
- assertIteratorResult(4, false, iter.throw(new Sentinel2));
- assertThrows(function() { iter.next(); }, Sentinel2);
- assertThrows(function() { iter.next(); }, Error);
+ function Test6(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertIteratorResult(4, false, iter.throw(new Sentinel2));
+ assertThrows(function() { iter.next(); }, Sentinel2);
+ assertThrows(function() { iter.next(); }, Error);
+ }
+ Test6(instantiate(g));
+
+ function Test7(iter) {
+ assertIteratorResult(1, false, iter.next());
+ assertIteratorResult(2, false, iter.next());
+ var exn = new Sentinel;
+ assertIteratorResult(exn, false, iter.throw(exn));
+ assertIteratorResult(3, false, iter.next());
+ assertIteratorResult(4, false, iter.throw(new Sentinel2));
+ assertThrows(function() { iter.next(); }, Sentinel2);
+ assertThrows(function() { iter.next(); }, Error);
+
+ }
+ Test7(instantiate(g));
// That's probably enough.
}
-TestNestedTry();
+TestNestedTry(function (g) { return g(); });
+TestNestedTry(function* (g) { return yield* g(); });
function TestRecursion() {
function TestNextRecursion() {
diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js
index 263154a..372ffdb 100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -88,7 +88,11 @@
}
var observer = createObserver();
+var observer2 = createObserver();
+
assertEquals("function", typeof observer.callback);
+assertEquals("function", typeof observer2.callback);
+
var obj = {};
function frozenFunction() {}
@@ -109,9 +113,15 @@
assertThrows(function() { Object.observe("non-object", observer.callback); }, TypeError);
assertThrows(function() { Object.observe(obj, nonFunction); }, TypeError);
assertThrows(function() { Object.observe(obj, frozenFunction); }, TypeError);
+assertThrows(function() { Object.observe(obj, function() {}, 1); }, TypeError);
+assertThrows(function() { Object.observe(obj, function() {}, [undefined]); }, TypeError);
+assertThrows(function() { Object.observe(obj, function() {}, [1]); }, TypeError);
+assertThrows(function() { Object.observe(obj, function() {}, ['foo', null]); }, TypeError);
+assertEquals(obj, Object.observe(obj, observer.callback, ['foo', 'bar', 'baz']));
+assertEquals(obj, Object.observe(obj, observer.callback, []));
+assertEquals(obj, Object.observe(obj, observer.callback, undefined));
assertEquals(obj, Object.observe(obj, observer.callback));
-
// Object.unobserve
assertThrows(function() { Object.unobserve(4, observer.callback); }, TypeError);
assertThrows(function() { Object.unobserve(obj, nonFunction); }, TypeError);
@@ -130,6 +140,20 @@
assertFalse(notifyDesc.enumerable);
assertThrows(function() { notifier.notify({}); }, TypeError);
assertThrows(function() { notifier.notify({ type: 4 }); }, TypeError);
+
+assertThrows(function() { notifier.performChange(1, function(){}); }, TypeError);
+assertThrows(function() { notifier.performChange(undefined, function(){}); }, TypeError);
+assertThrows(function() { notifier.performChange('foo', undefined); }, TypeError);
+assertThrows(function() { notifier.performChange('foo', 'bar'); }, TypeError);
+var testSelf = {};
+notifier.performChange('foo', function() {
+ assertTrue(testSelf === this);
+}, testSelf);
+var self = this;
+notifier.performChange('foo', function() {
+ assertTrue(self === this);
+});
+
var notify = notifier.notify;
assertThrows(function() { notify.call(undefined, { type: 'a' }); }, TypeError);
assertThrows(function() { notify.call(null, { type: 'a' }); }, TypeError);
@@ -195,7 +219,7 @@
Object.observe(obj, observer.callback);
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
});
Object.deliverChangeRecords(observer.callback);
observer.assertCalled();
@@ -205,7 +229,7 @@
reset();
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
});
Object.deliverChangeRecords(observer.callback);
observer.assertNotCalled();
@@ -216,7 +240,7 @@
Object.unobserve(obj, observer.callback);
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
});
Object.deliverChangeRecords(observer.callback);
observer.assertNotCalled();
@@ -225,11 +249,11 @@
// Re-observation works and only includes changeRecords after of call.
reset();
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
});
records = undefined;
Object.deliverChangeRecords(observer.callback);
@@ -240,42 +264,326 @@
reset();
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
val: 1
});
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
val: 2
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
val: 3
});
Object.unobserve(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
val: 4
});
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo',
+ type: 'updated',
val: 5
});
Object.unobserve(obj, observer.callback);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'foo', val: 1 },
- { object: obj, type: 'foo', val: 3 },
- { object: obj, type: 'foo', val: 5 }
+ { object: obj, type: 'updated', val: 1 },
+ { object: obj, type: 'updated', val: 3 },
+ { object: obj, type: 'updated', val: 5 }
]);
+// Accept
+reset();
+Object.observe(obj, observer.callback, []);
+Object.getNotifier(obj).notify({
+ type: 'new'
+});
+Object.getNotifier(obj).notify({
+ type: 'updated'
+});
+Object.getNotifier(obj).notify({
+ type: 'deleted'
+});
+Object.getNotifier(obj).notify({
+ type: 'reconfigured'
+});
+Object.getNotifier(obj).notify({
+ type: 'prototype'
+});
+Object.deliverChangeRecords(observer.callback);
+observer.assertNotCalled();
+
+reset();
+Object.observe(obj, observer.callback, ['new', 'deleted', 'prototype']);
+Object.getNotifier(obj).notify({
+ type: 'new'
+});
+Object.getNotifier(obj).notify({
+ type: 'updated'
+});
+Object.getNotifier(obj).notify({
+ type: 'deleted'
+});
+Object.getNotifier(obj).notify({
+ type: 'deleted'
+});
+Object.getNotifier(obj).notify({
+ type: 'reconfigured'
+});
+Object.getNotifier(obj).notify({
+ type: 'prototype'
+});
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+ { object: obj, type: 'new' },
+ { object: obj, type: 'deleted' },
+ { object: obj, type: 'deleted' },
+ { object: obj, type: 'prototype' }
+]);
+
+reset();
+Object.observe(obj, observer.callback, ['updated', 'foo']);
+Object.getNotifier(obj).notify({
+ type: 'new'
+});
+Object.getNotifier(obj).notify({
+ type: 'updated'
+});
+Object.getNotifier(obj).notify({
+ type: 'deleted'
+});
+Object.getNotifier(obj).notify({
+ type: 'foo'
+});
+Object.getNotifier(obj).notify({
+ type: 'bar'
+});
+Object.getNotifier(obj).notify({
+ type: 'foo'
+});
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+ { object: obj, type: 'updated' },
+ { object: obj, type: 'foo' },
+ { object: obj, type: 'foo' }
+]);
+
+reset();
+function Thingy(a, b, c) {
+ this.a = a;
+ this.b = b;
+}
+
+Thingy.MULTIPLY = 'multiply';
+Thingy.INCREMENT = 'increment';
+Thingy.INCREMENT_AND_MULTIPLY = 'incrementAndMultiply';
+
+Thingy.prototype = {
+ increment: function(amount) {
+ var notifier = Object.getNotifier(this);
+
+ notifier.performChange(Thingy.INCREMENT, function() {
+ this.a += amount;
+ this.b += amount;
+ }, this);
+
+ notifier.notify({
+ object: this,
+ type: Thingy.INCREMENT,
+ incremented: amount
+ });
+ },
+
+ multiply: function(amount) {
+ var notifier = Object.getNotifier(this);
+
+ notifier.performChange(Thingy.MULTIPLY, function() {
+ this.a *= amount;
+ this.b *= amount;
+ }, this);
+
+ notifier.notify({
+ object: this,
+ type: Thingy.MULTIPLY,
+ multiplied: amount
+ });
+ },
+
+ incrementAndMultiply: function(incAmount, multAmount) {
+ var notifier = Object.getNotifier(this);
+
+ notifier.performChange(Thingy.INCREMENT_AND_MULTIPLY, function() {
+ this.increment(incAmount);
+ this.multiply(multAmount);
+ }, this);
+
+ notifier.notify({
+ object: this,
+ type: Thingy.INCREMENT_AND_MULTIPLY,
+ incremented: incAmount,
+ multiplied: multAmount
+ });
+ }
+}
+
+Thingy.observe = function(thingy, callback) {
+ Object.observe(thingy, callback, [Thingy.INCREMENT,
+ Thingy.MULTIPLY,
+ Thingy.INCREMENT_AND_MULTIPLY,
+ 'updated']);
+}
+
+Thingy.unobserve = function(thingy, callback) {
+ Object.unobserve(thingy);
+}
+
+var thingy = new Thingy(2, 4);
+
+Object.observe(thingy, observer.callback);
+Thingy.observe(thingy, observer2.callback);
+thingy.increment(3); // { a: 5, b: 7 }
+thingy.b++; // { a: 5, b: 8 }
+thingy.multiply(2); // { a: 10, b: 16 }
+thingy.a++; // { a: 11, b: 16 }
+thingy.incrementAndMultiply(2, 2); // { a: 26, b: 36 }
+
+Object.deliverChangeRecords(observer.callback);
+Object.deliverChangeRecords(observer2.callback);
+observer.assertCallbackRecords([
+ { object: thingy, type: 'updated', name: 'a', oldValue: 2 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 4 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 7 },
+ { object: thingy, type: 'updated', name: 'a', oldValue: 5 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 8 },
+ { object: thingy, type: 'updated', name: 'a', oldValue: 10 },
+ { object: thingy, type: 'updated', name: 'a', oldValue: 11 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 16 },
+ { object: thingy, type: 'updated', name: 'a', oldValue: 13 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 18 },
+]);
+observer2.assertCallbackRecords([
+ { object: thingy, type: Thingy.INCREMENT, incremented: 3 },
+ { object: thingy, type: 'updated', name: 'b', oldValue: 7 },
+ { object: thingy, type: Thingy.MULTIPLY, multiplied: 2 },
+ { object: thingy, type: 'updated', name: 'a', oldValue: 10 },
+ {
+ object: thingy,
+ type: Thingy.INCREMENT_AND_MULTIPLY,
+ incremented: 2,
+ multiplied: 2
+ }
+]);
+
+
+reset();
+function RecursiveThingy() {}
+
+RecursiveThingy.MULTIPLY_FIRST_N = 'multiplyFirstN';
+
+RecursiveThingy.prototype = {
+ __proto__: Array.prototype,
+
+ multiplyFirstN: function(amount, n) {
+ if (!n)
+ return;
+ var notifier = Object.getNotifier(this);
+ notifier.performChange(RecursiveThingy.MULTIPLY_FIRST_N, function() {
+ this[n-1] = this[n-1]*amount;
+ this.multiplyFirstN(amount, n-1);
+ }, this);
+
+ notifier.notify({
+ object: this,
+ type: RecursiveThingy.MULTIPLY_FIRST_N,
+ multiplied: amount,
+ n: n
+ });
+ },
+}
+
+RecursiveThingy.observe = function(thingy, callback) {
+ Object.observe(thingy, callback, [RecursiveThingy.MULTIPLY_FIRST_N]);
+}
+
+RecursiveThingy.unobserve = function(thingy, callback) {
+ Object.unobserve(thingy);
+}
+
+var thingy = new RecursiveThingy;
+thingy.push(1, 2, 3, 4);
+
+Object.observe(thingy, observer.callback);
+RecursiveThingy.observe(thingy, observer2.callback);
+thingy.multiplyFirstN(2, 3); // [2, 4, 6, 4]
+
+Object.deliverChangeRecords(observer.callback);
+Object.deliverChangeRecords(observer2.callback);
+observer.assertCallbackRecords([
+ { object: thingy, type: 'updated', name: '2', oldValue: 3 },
+ { object: thingy, type: 'updated', name: '1', oldValue: 2 },
+ { object: thingy, type: 'updated', name: '0', oldValue: 1 }
+]);
+observer2.assertCallbackRecords([
+ { object: thingy, type: RecursiveThingy.MULTIPLY_FIRST_N, multiplied: 2, n: 3 }
+]);
+
+reset();
+function DeckSuit() {
+ this.push('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'A', 'Q', 'K');
+}
+
+DeckSuit.SHUFFLE = 'shuffle';
+
+DeckSuit.prototype = {
+ __proto__: Array.prototype,
+
+ shuffle: function() {
+ var notifier = Object.getNotifier(this);
+ notifier.performChange(DeckSuit.SHUFFLE, function() {
+ this.reverse();
+ this.sort(function() { return Math.random()* 2 - 1; });
+ var cut = this.splice(0, 6);
+ Array.prototype.push.apply(this, cut);
+ this.reverse();
+ this.sort(function() { return Math.random()* 2 - 1; });
+ var cut = this.splice(0, 6);
+ Array.prototype.push.apply(this, cut);
+ this.reverse();
+ this.sort(function() { return Math.random()* 2 - 1; });
+ }, this);
+
+ notifier.notify({
+ object: this,
+ type: DeckSuit.SHUFFLE
+ });
+ },
+}
+
+DeckSuit.observe = function(thingy, callback) {
+ Object.observe(thingy, callback, [DeckSuit.SHUFFLE]);
+}
+
+DeckSuit.unobserve = function(thingy, callback) {
+ Object.unobserve(thingy);
+}
+
+var deck = new DeckSuit;
+
+DeckSuit.observe(deck, observer2.callback);
+deck.shuffle();
+
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: deck, type: DeckSuit.SHUFFLE }
+]);
// Observing multiple objects; records appear in order.
reset();
@@ -285,20 +593,20 @@
Object.observe(obj3, observer.callback);
Object.observe(obj2, observer.callback);
Object.getNotifier(obj).notify({
- type: 'foo1',
+ type: 'new',
});
Object.getNotifier(obj2).notify({
- type: 'foo2',
+ type: 'updated',
});
Object.getNotifier(obj3).notify({
- type: 'foo3',
+ type: 'deleted',
});
Object.observe(obj3, observer.callback);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
- { object: obj, type: 'foo1' },
- { object: obj2, type: 'foo2' },
- { object: obj3, type: 'foo3' }
+ { object: obj, type: 'new' },
+ { object: obj2, type: 'updated' },
+ { object: obj3, type: 'deleted' }
]);
@@ -760,13 +1068,22 @@
reset();
var array = [1, 2];
Object.observe(array, observer.callback);
+Array.observe(array, observer2.callback);
array.push(3, 4);
+array.push(5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: array, name: '2', type: 'new' },
{ object: array, name: 'length', type: 'updated', oldValue: 2 },
{ object: array, name: '3', type: 'new' },
{ object: array, name: 'length', type: 'updated', oldValue: 3 },
+ { object: array, name: '4', type: 'new' },
+ { object: array, name: 'length', type: 'updated', oldValue: 4 },
+]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 2, removed: [], addedCount: 2 },
+ { object: array, type: 'splice', index: 4, removed: [], addedCount: 1 }
]);
// Pop
diff --git a/test/mjsunit/regress/regress-2686.js b/test/mjsunit/regress/regress-2686.js
new file mode 100644
index 0000000..bd6106f
--- /dev/null
+++ b/test/mjsunit/regress/regress-2686.js
@@ -0,0 +1,32 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check Function doesn't use String.prototype.indexOf.
+
+assertThrows(function() { Function('){ function foo(', '}') }, SyntaxError);
+String.prototype.indexOf = function () { return -1; }
+assertThrows(function() { Function('){ function foo(', '}') }, SyntaxError);
diff --git a/test/mjsunit/regress/regress-seqstrsetchar-ex1.js b/test/mjsunit/regress/regress-seqstrsetchar-ex1.js
new file mode 100644
index 0000000..be54be6
--- /dev/null
+++ b/test/mjsunit/regress/regress-seqstrsetchar-ex1.js
@@ -0,0 +1,60 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// stubbed version of ToNumber
+function ToNumber(x) {
+ return 311;
+}
+
+// Reduced version of String.fromCharCode;
+// does not actually do the same calculation but exhibits untagging bug.
+function StringFromCharCode(code) {
+ var n = %_ArgumentsLength();
+ var one_byte = %NewString(n, true);
+ var i;
+ for (i = 0; i < n; i++) {
+ var code = %_Arguments(i);
+ if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff;
+ if (code > 0xff) break;
+ }
+
+ var two_byte = %NewString(n - i, false);
+ for (var j = 0; i < n; i++, j++) {
+ var code = %_Arguments(i);
+ %_TwoByteSeqStringSetChar(two_byte, j, code);
+ }
+ return one_byte + two_byte;
+}
+
+StringFromCharCode(0xFFF, 0xFFF);
+StringFromCharCode(0x7C, 0x7C);
+%OptimizeFunctionOnNextCall(StringFromCharCode);
+StringFromCharCode(0x7C, 0x7C);
+StringFromCharCode(0xFFF, 0xFFF);
+
diff --git a/test/mjsunit/regress/regress-seqstrsetchar-ex2.js b/test/mjsunit/regress/regress-seqstrsetchar-ex2.js
new file mode 100644
index 0000000..6acc2f2
--- /dev/null
+++ b/test/mjsunit/regress/regress-seqstrsetchar-ex2.js
@@ -0,0 +1,35 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+String.fromCharCode(0xFFF, 0xFFF);
+String.fromCharCode(0x7C, 0x7C);
+%OptimizeFunctionOnNextCall(String.fromCharCode);
+String.fromCharCode(0x7C, 0x7C);
+String.fromCharCode(0xFFF, 0xFFF);
+
diff --git a/test/mjsunit/track-fields.js b/test/mjsunit/track-fields.js
index bcf37ae..74389d9 100644
--- a/test/mjsunit/track-fields.js
+++ b/test/mjsunit/track-fields.js
@@ -261,3 +261,48 @@
assertEquals(100, o20.smi);
assertEquals(100, o20.dbl);
assertEquals(100, o20.dbl);
+
+function attr_mismatch_obj(v, writable) {
+ var o = {};
+ o.some_value = v;
+ Object.defineProperty(o, "second_value", {value:10, writable:writable});
+ return o;
+}
+
+function is_writable(o, p) {
+ return Object.getOwnPropertyDescriptor(o,p).writable;
+}
+
+var writable = attr_mismatch_obj(10, true);
+var non_writable1 = attr_mismatch_obj(10.5, false);
+assertTrue(is_writable(writable,"second_value"));
+assertFalse(is_writable(non_writable1,"second_value"));
+writable.some_value = 20.5;
+assertTrue(is_writable(writable,"second_value"));
+var non_writable2 = attr_mismatch_obj(10.5, false);
+assertTrue(%HaveSameMap(non_writable1, non_writable2));
+
+function test_f(v) {
+ var o = {};
+ o.vbf = v;
+ o.func = test_f;
+ return o;
+}
+
+function test_fic(o) {
+ return o.vbf;
+}
+
+var ftest1 = test_f(10);
+var ftest2 = test_f(10);
+var ftest3 = test_f(10.5);
+var ftest4 = test_f(10);
+assertFalse(%HaveSameMap(ftest1, ftest3));
+assertTrue(%HaveSameMap(ftest3, ftest4));
+ftest2.func = is_writable;
+test_fic(ftest1);
+test_fic(ftest2);
+test_fic(ftest3);
+test_fic(ftest4);
+assertTrue(%HaveSameMap(ftest1, ftest3));
+assertTrue(%HaveSameMap(ftest3, ftest4));
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index fc6296a..ba8312b 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -27,978 +27,900 @@
{
'includes': ['../../build/common.gypi'],
- 'conditions': [
- ['use_system_v8==0', {
- 'targets': [
+ 'targets': [
+ {
+ 'target_name': 'v8',
+ 'dependencies_traverse': 1,
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ['v8_use_snapshot=="true"', {
+ # The dependency on v8_base should come from a transitive
+ # dependency however the Android toolchain requires libv8_base.a
+ # to appear before libv8_snapshot.a so it's listed explicitly.
+ 'dependencies': ['v8_base.<(v8_target_arch)', 'v8_snapshot'],
+ },
{
- 'target_name': 'v8',
- 'dependencies_traverse': 1,
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- }, {
- 'toolsets': ['target'],
- }],
- ['v8_use_snapshot=="true"', {
- # The dependency on v8_base should come from a transitive
- # dependency however the Android toolchain requires libv8_base.a
- # to appear before libv8_snapshot.a so it's listed explicitly.
- 'dependencies': ['v8_base.<(v8_target_arch)', 'v8_snapshot'],
- },
- {
- # The dependency on v8_base should come from a transitive
- # dependency however the Android toolchain requires libv8_base.a
- # to appear before libv8_snapshot.a so it's listed explicitly.
- 'dependencies': [
- 'v8_base.<(v8_target_arch)',
- 'v8_nosnapshot.<(v8_target_arch)',
- ],
- }],
- ['component=="shared_library"', {
- 'type': '<(component)',
- 'sources': [
- # Note: on non-Windows we still build this file so that gyp
- # has some sources to link into the component.
- '../../src/v8dll-main.cc',
- ],
- 'defines': [
- 'V8_SHARED',
- 'BUILDING_V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'V8_SHARED',
- 'USING_V8_SHARED',
- ],
- },
- 'target_conditions': [
- ['OS=="android" and _toolset=="target"', {
- 'libraries': [
- '-llog',
- ],
- 'include_dirs': [
- 'src/common/android/include',
- ],
- }],
- ],
- 'conditions': [
- ['OS=="mac"', {
- 'xcode_settings': {
- 'OTHER_LDFLAGS': ['-dynamiclib', '-all_load']
- },
- }],
- ['soname_version!=""', {
- 'product_extension': 'so.<(soname_version)',
- }],
- ],
- },
- {
- 'type': 'none',
- }],
+ # The dependency on v8_base should come from a transitive
+ # dependency however the Android toolchain requires libv8_base.a
+ # to appear before libv8_snapshot.a so it's listed explicitly.
+ 'dependencies': [
+ 'v8_base.<(v8_target_arch)',
+ 'v8_nosnapshot.<(v8_target_arch)',
+ ],
+ }],
+ ['component=="shared_library"', {
+ 'type': '<(component)',
+ 'sources': [
+ # Note: on non-Windows we still build this file so that gyp
+ # has some sources to link into the component.
+ '../../src/v8dll-main.cc',
+ ],
+ 'defines': [
+ 'V8_SHARED',
+ 'BUILDING_V8_SHARED',
],
'direct_dependent_settings': {
- 'include_dirs': [
- '../../include',
+ 'defines': [
+ 'V8_SHARED',
+ 'USING_V8_SHARED',
],
},
- },
- {
- 'target_name': 'v8_snapshot',
- 'type': 'static_library',
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- 'dependencies': [
- 'mksnapshot.<(v8_target_arch)#host',
- 'js2c#host',
+ 'target_conditions': [
+ ['OS=="android" and _toolset=="target"', {
+ 'libraries': [
+ '-llog',
],
- }, {
- 'toolsets': ['target'],
- 'dependencies': ['mksnapshot.<(v8_target_arch)', 'js2c'],
+ 'include_dirs': [
+ 'src/common/android/include',
+ ],
}],
- ['component=="shared_library"', {
- 'defines': [
- 'V8_SHARED',
- 'BUILDING_V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'V8_SHARED',
- 'USING_V8_SHARED',
- ],
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': ['-dynamiclib', '-all_load']
},
}],
+ ['soname_version!=""', {
+ 'product_extension': 'so.<(soname_version)',
+ }],
],
+ },
+ {
+ 'type': 'none',
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../../include',
+ ],
+ },
+ },
+ {
+ 'target_name': 'v8_snapshot',
+ 'type': 'static_library',
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
'dependencies': [
- 'v8_base.<(v8_target_arch)',
+ 'mksnapshot.<(v8_target_arch)#host',
+ 'js2c#host',
],
- 'include_dirs+': [
- '../../src',
+ }, {
+ 'toolsets': ['target'],
+ 'dependencies': ['mksnapshot.<(v8_target_arch)', 'js2c'],
+ }],
+ ['component=="shared_library"', {
+ 'defines': [
+ 'V8_SHARED',
+ 'BUILDING_V8_SHARED',
],
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
- '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'V8_SHARED',
+ 'USING_V8_SHARED',
+ ],
+ },
+ }],
+ ],
+ 'dependencies': [
+ 'v8_base.<(v8_target_arch)',
+ ],
+ 'include_dirs+': [
+ '../../src',
+ ],
+ 'sources': [
+ '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ '<(INTERMEDIATE_DIR)/snapshot.cc',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'run_mksnapshot',
+ 'inputs': [
+ '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot.<(v8_target_arch)<(EXECUTABLE_SUFFIX)',
+ ],
+ 'outputs': [
'<(INTERMEDIATE_DIR)/snapshot.cc',
],
- 'actions': [
- {
- 'action_name': 'run_mksnapshot',
- 'inputs': [
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot.<(v8_target_arch)<(EXECUTABLE_SUFFIX)',
- ],
- 'outputs': [
- '<(INTERMEDIATE_DIR)/snapshot.cc',
- ],
- 'variables': {
- 'mksnapshot_flags': [
- '--log-snapshot-positions',
- '--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
- ],
- },
- 'action': [
- '<@(_inputs)',
- '<@(mksnapshot_flags)',
- '<@(_outputs)'
+ 'variables': {
+ 'mksnapshot_flags': [
+ '--log-snapshot-positions',
+ '--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
+ ],
+ },
+ 'action': [
+ '<@(_inputs)',
+ '<@(mksnapshot_flags)',
+ '<@(_outputs)'
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'v8_nosnapshot.<(v8_target_arch)',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'v8_base.<(v8_target_arch)',
+ ],
+ 'include_dirs+': [
+ '../../src',
+ ],
+ 'sources': [
+ '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ '../../src/snapshot-empty.cc',
+ ],
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ 'dependencies': ['js2c#host'],
+ }, {
+ 'toolsets': ['target'],
+ 'dependencies': ['js2c'],
+ }],
+ ['component=="shared_library"', {
+ 'defines': [
+ 'BUILDING_V8_SHARED',
+ 'V8_SHARED',
+ ],
+ }],
+ ]
+ },
+ {
+ 'target_name': 'v8_base.<(v8_target_arch)',
+ 'type': 'static_library',
+ 'variables': {
+ 'optimize': 'max',
+ },
+ 'include_dirs+': [
+ '../../src',
+ ],
+ 'sources': [ ### gcmole(all) ###
+ '../../src/accessors.cc',
+ '../../src/accessors.h',
+ '../../src/allocation.cc',
+ '../../src/allocation.h',
+ '../../src/api.cc',
+ '../../src/api.h',
+ '../../src/apiutils.h',
+ '../../src/arguments.h',
+ '../../src/assembler.cc',
+ '../../src/assembler.h',
+ '../../src/ast.cc',
+ '../../src/ast.h',
+ '../../src/atomicops.h',
+ '../../src/atomicops_internals_x86_gcc.cc',
+ '../../src/bignum-dtoa.cc',
+ '../../src/bignum-dtoa.h',
+ '../../src/bignum.cc',
+ '../../src/bignum.h',
+ '../../src/bootstrapper.cc',
+ '../../src/bootstrapper.h',
+ '../../src/builtins.cc',
+ '../../src/builtins.h',
+ '../../src/bytecodes-irregexp.h',
+ '../../src/cached-powers.cc',
+ '../../src/cached-powers.h',
+ '../../src/char-predicates-inl.h',
+ '../../src/char-predicates.h',
+ '../../src/checks.cc',
+ '../../src/checks.h',
+ '../../src/circular-queue-inl.h',
+ '../../src/circular-queue.cc',
+ '../../src/circular-queue.h',
+ '../../src/code-stubs.cc',
+ '../../src/code-stubs.h',
+ '../../src/code-stubs-hydrogen.cc',
+ '../../src/code.h',
+ '../../src/codegen.cc',
+ '../../src/codegen.h',
+ '../../src/compilation-cache.cc',
+ '../../src/compilation-cache.h',
+ '../../src/compiler.cc',
+ '../../src/compiler.h',
+ '../../src/contexts.cc',
+ '../../src/contexts.h',
+ '../../src/conversions-inl.h',
+ '../../src/conversions.cc',
+ '../../src/conversions.h',
+ '../../src/counters.cc',
+ '../../src/counters.h',
+ '../../src/cpu-profiler-inl.h',
+ '../../src/cpu-profiler.cc',
+ '../../src/cpu-profiler.h',
+ '../../src/cpu.h',
+ '../../src/data-flow.cc',
+ '../../src/data-flow.h',
+ '../../src/date.cc',
+ '../../src/date.h',
+ '../../src/dateparser-inl.h',
+ '../../src/dateparser.cc',
+ '../../src/dateparser.h',
+ '../../src/debug-agent.cc',
+ '../../src/debug-agent.h',
+ '../../src/debug.cc',
+ '../../src/debug.h',
+ '../../src/deoptimizer.cc',
+ '../../src/deoptimizer.h',
+ '../../src/disasm.h',
+ '../../src/disassembler.cc',
+ '../../src/disassembler.h',
+ '../../src/diy-fp.cc',
+ '../../src/diy-fp.h',
+ '../../src/double.h',
+ '../../src/dtoa.cc',
+ '../../src/dtoa.h',
+ '../../src/elements-kind.cc',
+ '../../src/elements-kind.h',
+ '../../src/elements.cc',
+ '../../src/elements.h',
+ '../../src/execution.cc',
+ '../../src/execution.h',
+ '../../src/extensions/externalize-string-extension.cc',
+ '../../src/extensions/externalize-string-extension.h',
+ '../../src/extensions/gc-extension.cc',
+ '../../src/extensions/gc-extension.h',
+ '../../src/extensions/statistics-extension.cc',
+ '../../src/extensions/statistics-extension.h',
+ '../../src/factory.cc',
+ '../../src/factory.h',
+ '../../src/fast-dtoa.cc',
+ '../../src/fast-dtoa.h',
+ '../../src/fixed-dtoa.cc',
+ '../../src/fixed-dtoa.h',
+ '../../src/flag-definitions.h',
+ '../../src/flags.cc',
+ '../../src/flags.h',
+ '../../src/frames-inl.h',
+ '../../src/frames.cc',
+ '../../src/frames.h',
+ '../../src/full-codegen.cc',
+ '../../src/full-codegen.h',
+ '../../src/func-name-inferrer.cc',
+ '../../src/func-name-inferrer.h',
+ '../../src/gdb-jit.cc',
+ '../../src/gdb-jit.h',
+ '../../src/global-handles.cc',
+ '../../src/global-handles.h',
+ '../../src/globals.h',
+ '../../src/handles-inl.h',
+ '../../src/handles.cc',
+ '../../src/handles.h',
+ '../../src/hashmap.h',
+ '../../src/heap-inl.h',
+ '../../src/heap-profiler.cc',
+ '../../src/heap-profiler.h',
+ '../../src/heap-snapshot-generator-inl.h',
+ '../../src/heap-snapshot-generator.cc',
+ '../../src/heap-snapshot-generator.h',
+ '../../src/heap.cc',
+ '../../src/heap.h',
+ '../../src/hydrogen-instructions.cc',
+ '../../src/hydrogen-instructions.h',
+ '../../src/hydrogen.cc',
+ '../../src/hydrogen.h',
+ '../../src/ic-inl.h',
+ '../../src/ic.cc',
+ '../../src/ic.h',
+ '../../src/incremental-marking.cc',
+ '../../src/incremental-marking.h',
+ '../../src/interface.cc',
+ '../../src/interface.h',
+ '../../src/interpreter-irregexp.cc',
+ '../../src/interpreter-irregexp.h',
+ '../../src/isolate.cc',
+ '../../src/isolate.h',
+ '../../src/json-parser.h',
+ '../../src/json-stringifier.h',
+ '../../src/jsregexp-inl.h',
+ '../../src/jsregexp.cc',
+ '../../src/jsregexp.h',
+ '../../src/lazy-instance.h',
+ '../../src/list-inl.h',
+ '../../src/list.h',
+ '../../src/lithium-allocator-inl.h',
+ '../../src/lithium-allocator.cc',
+ '../../src/lithium-allocator.h',
+ '../../src/lithium.cc',
+ '../../src/lithium.h',
+ '../../src/liveedit.cc',
+ '../../src/liveedit.h',
+ '../../src/log-inl.h',
+ '../../src/log-utils.cc',
+ '../../src/log-utils.h',
+ '../../src/log.cc',
+ '../../src/log.h',
+ '../../src/macro-assembler.h',
+ '../../src/mark-compact.cc',
+ '../../src/mark-compact.h',
+ '../../src/marking-thread.h',
+ '../../src/marking-thread.cc',
+ '../../src/messages.cc',
+ '../../src/messages.h',
+ '../../src/natives.h',
+ '../../src/objects-debug.cc',
+ '../../src/objects-inl.h',
+ '../../src/objects-printer.cc',
+ '../../src/objects-visiting.cc',
+ '../../src/objects-visiting.h',
+ '../../src/objects.cc',
+ '../../src/objects.h',
+ '../../src/once.cc',
+ '../../src/once.h',
+ '../../src/optimizing-compiler-thread.h',
+ '../../src/optimizing-compiler-thread.cc',
+ '../../src/parser.cc',
+ '../../src/parser.h',
+ '../../src/platform-posix.h',
+ '../../src/platform-tls-mac.h',
+ '../../src/platform-tls-win32.h',
+ '../../src/platform-tls.h',
+ '../../src/platform.h',
+ '../../src/preparse-data-format.h',
+ '../../src/preparse-data.cc',
+ '../../src/preparse-data.h',
+ '../../src/preparser.cc',
+ '../../src/preparser.h',
+ '../../src/prettyprinter.cc',
+ '../../src/prettyprinter.h',
+ '../../src/profile-generator-inl.h',
+ '../../src/profile-generator.cc',
+ '../../src/profile-generator.h',
+ '../../src/property-details.h',
+ '../../src/property.cc',
+ '../../src/property.h',
+ '../../src/regexp-macro-assembler-irregexp-inl.h',
+ '../../src/regexp-macro-assembler-irregexp.cc',
+ '../../src/regexp-macro-assembler-irregexp.h',
+ '../../src/regexp-macro-assembler-tracer.cc',
+ '../../src/regexp-macro-assembler-tracer.h',
+ '../../src/regexp-macro-assembler.cc',
+ '../../src/regexp-macro-assembler.h',
+ '../../src/regexp-stack.cc',
+ '../../src/regexp-stack.h',
+ '../../src/rewriter.cc',
+ '../../src/rewriter.h',
+ '../../src/runtime-profiler.cc',
+ '../../src/runtime-profiler.h',
+ '../../src/runtime.cc',
+ '../../src/runtime.h',
+ '../../src/safepoint-table.cc',
+ '../../src/safepoint-table.h',
+ '../../src/sampler.cc',
+ '../../src/sampler.h',
+ '../../src/scanner-character-streams.cc',
+ '../../src/scanner-character-streams.h',
+ '../../src/scanner.cc',
+ '../../src/scanner.h',
+ '../../src/scopeinfo.cc',
+ '../../src/scopeinfo.h',
+ '../../src/scopes.cc',
+ '../../src/scopes.h',
+ '../../src/serialize.cc',
+ '../../src/serialize.h',
+ '../../src/small-pointer-list.h',
+ '../../src/smart-pointers.h',
+ '../../src/snapshot-common.cc',
+ '../../src/snapshot.h',
+ '../../src/spaces-inl.h',
+ '../../src/spaces.cc',
+ '../../src/spaces.h',
+ '../../src/store-buffer-inl.h',
+ '../../src/store-buffer.cc',
+ '../../src/store-buffer.h',
+ '../../src/string-search.cc',
+ '../../src/string-search.h',
+ '../../src/string-stream.cc',
+ '../../src/string-stream.h',
+ '../../src/strtod.cc',
+ '../../src/strtod.h',
+ '../../src/stub-cache.cc',
+ '../../src/stub-cache.h',
+ '../../src/sweeper-thread.h',
+ '../../src/sweeper-thread.cc',
+ '../../src/token.cc',
+ '../../src/token.h',
+ '../../src/transitions-inl.h',
+ '../../src/transitions.cc',
+ '../../src/transitions.h',
+ '../../src/type-info.cc',
+ '../../src/type-info.h',
+ '../../src/unbound-queue-inl.h',
+ '../../src/unbound-queue.h',
+ '../../src/unicode-inl.h',
+ '../../src/unicode.cc',
+ '../../src/unicode.h',
+ '../../src/uri.h',
+ '../../src/utils-inl.h',
+ '../../src/utils.cc',
+ '../../src/utils.h',
+ '../../src/v8-counters.cc',
+ '../../src/v8-counters.h',
+ '../../src/v8.cc',
+ '../../src/v8.h',
+ '../../src/v8checks.h',
+ '../../src/v8conversions.cc',
+ '../../src/v8conversions.h',
+ '../../src/v8globals.h',
+ '../../src/v8memory.h',
+ '../../src/v8threads.cc',
+ '../../src/v8threads.h',
+ '../../src/v8utils.cc',
+ '../../src/v8utils.h',
+ '../../src/variables.cc',
+ '../../src/variables.h',
+ '../../src/version.cc',
+ '../../src/version.h',
+ '../../src/vm-state-inl.h',
+ '../../src/vm-state.h',
+ '../../src/zone-inl.h',
+ '../../src/zone.cc',
+ '../../src/zone.h',
+ ],
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ['v8_target_arch=="arm"', {
+ 'sources': [ ### gcmole(arch:arm) ###
+ '../../src/arm/assembler-arm-inl.h',
+ '../../src/arm/assembler-arm.cc',
+ '../../src/arm/assembler-arm.h',
+ '../../src/arm/builtins-arm.cc',
+ '../../src/arm/code-stubs-arm.cc',
+ '../../src/arm/code-stubs-arm.h',
+ '../../src/arm/codegen-arm.cc',
+ '../../src/arm/codegen-arm.h',
+ '../../src/arm/constants-arm.h',
+ '../../src/arm/constants-arm.cc',
+ '../../src/arm/cpu-arm.cc',
+ '../../src/arm/debug-arm.cc',
+ '../../src/arm/deoptimizer-arm.cc',
+ '../../src/arm/disasm-arm.cc',
+ '../../src/arm/frames-arm.cc',
+ '../../src/arm/frames-arm.h',
+ '../../src/arm/full-codegen-arm.cc',
+ '../../src/arm/ic-arm.cc',
+ '../../src/arm/lithium-arm.cc',
+ '../../src/arm/lithium-arm.h',
+ '../../src/arm/lithium-codegen-arm.cc',
+ '../../src/arm/lithium-codegen-arm.h',
+ '../../src/arm/lithium-gap-resolver-arm.cc',
+ '../../src/arm/lithium-gap-resolver-arm.h',
+ '../../src/arm/macro-assembler-arm.cc',
+ '../../src/arm/macro-assembler-arm.h',
+ '../../src/arm/regexp-macro-assembler-arm.cc',
+ '../../src/arm/regexp-macro-assembler-arm.h',
+ '../../src/arm/simulator-arm.cc',
+ '../../src/arm/stub-cache-arm.cc',
+ ],
+ }],
+ ['v8_target_arch=="ia32" or v8_target_arch=="mac" or OS=="mac"', {
+ 'sources': [ ### gcmole(arch:ia32) ###
+ '../../src/ia32/assembler-ia32-inl.h',
+ '../../src/ia32/assembler-ia32.cc',
+ '../../src/ia32/assembler-ia32.h',
+ '../../src/ia32/builtins-ia32.cc',
+ '../../src/ia32/code-stubs-ia32.cc',
+ '../../src/ia32/code-stubs-ia32.h',
+ '../../src/ia32/codegen-ia32.cc',
+ '../../src/ia32/codegen-ia32.h',
+ '../../src/ia32/cpu-ia32.cc',
+ '../../src/ia32/debug-ia32.cc',
+ '../../src/ia32/deoptimizer-ia32.cc',
+ '../../src/ia32/disasm-ia32.cc',
+ '../../src/ia32/frames-ia32.cc',
+ '../../src/ia32/frames-ia32.h',
+ '../../src/ia32/full-codegen-ia32.cc',
+ '../../src/ia32/ic-ia32.cc',
+ '../../src/ia32/lithium-codegen-ia32.cc',
+ '../../src/ia32/lithium-codegen-ia32.h',
+ '../../src/ia32/lithium-gap-resolver-ia32.cc',
+ '../../src/ia32/lithium-gap-resolver-ia32.h',
+ '../../src/ia32/lithium-ia32.cc',
+ '../../src/ia32/lithium-ia32.h',
+ '../../src/ia32/macro-assembler-ia32.cc',
+ '../../src/ia32/macro-assembler-ia32.h',
+ '../../src/ia32/regexp-macro-assembler-ia32.cc',
+ '../../src/ia32/regexp-macro-assembler-ia32.h',
+ '../../src/ia32/stub-cache-ia32.cc',
+ ],
+ }],
+ ['v8_target_arch=="mipsel"', {
+ 'sources': [ ### gcmole(arch:mipsel) ###
+ '../../src/mips/assembler-mips.cc',
+ '../../src/mips/assembler-mips.h',
+ '../../src/mips/assembler-mips-inl.h',
+ '../../src/mips/builtins-mips.cc',
+ '../../src/mips/codegen-mips.cc',
+ '../../src/mips/codegen-mips.h',
+ '../../src/mips/code-stubs-mips.cc',
+ '../../src/mips/code-stubs-mips.h',
+ '../../src/mips/constants-mips.cc',
+ '../../src/mips/constants-mips.h',
+ '../../src/mips/cpu-mips.cc',
+ '../../src/mips/debug-mips.cc',
+ '../../src/mips/deoptimizer-mips.cc',
+ '../../src/mips/disasm-mips.cc',
+ '../../src/mips/frames-mips.cc',
+ '../../src/mips/frames-mips.h',
+ '../../src/mips/full-codegen-mips.cc',
+ '../../src/mips/ic-mips.cc',
+ '../../src/mips/lithium-codegen-mips.cc',
+ '../../src/mips/lithium-codegen-mips.h',
+ '../../src/mips/lithium-gap-resolver-mips.cc',
+ '../../src/mips/lithium-gap-resolver-mips.h',
+ '../../src/mips/lithium-mips.cc',
+ '../../src/mips/lithium-mips.h',
+ '../../src/mips/macro-assembler-mips.cc',
+ '../../src/mips/macro-assembler-mips.h',
+ '../../src/mips/regexp-macro-assembler-mips.cc',
+ '../../src/mips/regexp-macro-assembler-mips.h',
+ '../../src/mips/simulator-mips.cc',
+ '../../src/mips/stub-cache-mips.cc',
+ ],
+ }],
+ ['v8_target_arch=="x64" or v8_target_arch=="mac" or OS=="mac"', {
+ 'sources': [ ### gcmole(arch:x64) ###
+ '../../src/x64/assembler-x64-inl.h',
+ '../../src/x64/assembler-x64.cc',
+ '../../src/x64/assembler-x64.h',
+ '../../src/x64/builtins-x64.cc',
+ '../../src/x64/code-stubs-x64.cc',
+ '../../src/x64/code-stubs-x64.h',
+ '../../src/x64/codegen-x64.cc',
+ '../../src/x64/codegen-x64.h',
+ '../../src/x64/cpu-x64.cc',
+ '../../src/x64/debug-x64.cc',
+ '../../src/x64/deoptimizer-x64.cc',
+ '../../src/x64/disasm-x64.cc',
+ '../../src/x64/frames-x64.cc',
+ '../../src/x64/frames-x64.h',
+ '../../src/x64/full-codegen-x64.cc',
+ '../../src/x64/ic-x64.cc',
+ '../../src/x64/lithium-codegen-x64.cc',
+ '../../src/x64/lithium-codegen-x64.h',
+ '../../src/x64/lithium-gap-resolver-x64.cc',
+ '../../src/x64/lithium-gap-resolver-x64.h',
+ '../../src/x64/lithium-x64.cc',
+ '../../src/x64/lithium-x64.h',
+ '../../src/x64/macro-assembler-x64.cc',
+ '../../src/x64/macro-assembler-x64.h',
+ '../../src/x64/regexp-macro-assembler-x64.cc',
+ '../../src/x64/regexp-macro-assembler-x64.h',
+ '../../src/x64/stub-cache-x64.cc',
+ ],
+ }],
+ ['OS=="linux"', {
+ 'link_settings': {
+ 'conditions': [
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]
+ }],
],
},
- ],
- },
- {
- 'target_name': 'v8_nosnapshot.<(v8_target_arch)',
- 'type': 'static_library',
- 'dependencies': [
- 'v8_base.<(v8_target_arch)',
- ],
- 'include_dirs+': [
- '../../src',
- ],
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
- '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
- '../../src/snapshot-empty.cc',
- ],
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- 'dependencies': ['js2c#host'],
- }, {
- 'toolsets': ['target'],
- 'dependencies': ['js2c'],
- }],
- ['component=="shared_library"', {
- 'defines': [
- 'BUILDING_V8_SHARED',
- 'V8_SHARED',
- ],
- }],
- ]
- },
- {
- 'target_name': 'v8_base.<(v8_target_arch)',
- 'type': 'static_library',
- 'variables': {
- 'optimize': 'max',
- },
- 'include_dirs+': [
- '../../src',
- ],
- 'sources': [ ### gcmole(all) ###
- '../../src/accessors.cc',
- '../../src/accessors.h',
- '../../src/allocation.cc',
- '../../src/allocation.h',
- '../../src/api.cc',
- '../../src/api.h',
- '../../src/apiutils.h',
- '../../src/arguments.h',
- '../../src/assembler.cc',
- '../../src/assembler.h',
- '../../src/ast.cc',
- '../../src/ast.h',
- '../../src/atomicops.h',
- '../../src/atomicops_internals_x86_gcc.cc',
- '../../src/bignum-dtoa.cc',
- '../../src/bignum-dtoa.h',
- '../../src/bignum.cc',
- '../../src/bignum.h',
- '../../src/bootstrapper.cc',
- '../../src/bootstrapper.h',
- '../../src/builtins.cc',
- '../../src/builtins.h',
- '../../src/bytecodes-irregexp.h',
- '../../src/cached-powers.cc',
- '../../src/cached-powers.h',
- '../../src/char-predicates-inl.h',
- '../../src/char-predicates.h',
- '../../src/checks.cc',
- '../../src/checks.h',
- '../../src/circular-queue-inl.h',
- '../../src/circular-queue.cc',
- '../../src/circular-queue.h',
- '../../src/code-stubs.cc',
- '../../src/code-stubs.h',
- '../../src/code-stubs-hydrogen.cc',
- '../../src/code.h',
- '../../src/codegen.cc',
- '../../src/codegen.h',
- '../../src/compilation-cache.cc',
- '../../src/compilation-cache.h',
- '../../src/compiler.cc',
- '../../src/compiler.h',
- '../../src/contexts.cc',
- '../../src/contexts.h',
- '../../src/conversions-inl.h',
- '../../src/conversions.cc',
- '../../src/conversions.h',
- '../../src/counters.cc',
- '../../src/counters.h',
- '../../src/cpu-profiler-inl.h',
- '../../src/cpu-profiler.cc',
- '../../src/cpu-profiler.h',
- '../../src/cpu.h',
- '../../src/data-flow.cc',
- '../../src/data-flow.h',
- '../../src/date.cc',
- '../../src/date.h',
- '../../src/dateparser-inl.h',
- '../../src/dateparser.cc',
- '../../src/dateparser.h',
- '../../src/debug-agent.cc',
- '../../src/debug-agent.h',
- '../../src/debug.cc',
- '../../src/debug.h',
- '../../src/deoptimizer.cc',
- '../../src/deoptimizer.h',
- '../../src/disasm.h',
- '../../src/disassembler.cc',
- '../../src/disassembler.h',
- '../../src/diy-fp.cc',
- '../../src/diy-fp.h',
- '../../src/double.h',
- '../../src/dtoa.cc',
- '../../src/dtoa.h',
- '../../src/elements-kind.cc',
- '../../src/elements-kind.h',
- '../../src/elements.cc',
- '../../src/elements.h',
- '../../src/execution.cc',
- '../../src/execution.h',
- '../../src/extensions/externalize-string-extension.cc',
- '../../src/extensions/externalize-string-extension.h',
- '../../src/extensions/gc-extension.cc',
- '../../src/extensions/gc-extension.h',
- '../../src/extensions/statistics-extension.cc',
- '../../src/extensions/statistics-extension.h',
- '../../src/factory.cc',
- '../../src/factory.h',
- '../../src/fast-dtoa.cc',
- '../../src/fast-dtoa.h',
- '../../src/fixed-dtoa.cc',
- '../../src/fixed-dtoa.h',
- '../../src/flag-definitions.h',
- '../../src/flags.cc',
- '../../src/flags.h',
- '../../src/frames-inl.h',
- '../../src/frames.cc',
- '../../src/frames.h',
- '../../src/full-codegen.cc',
- '../../src/full-codegen.h',
- '../../src/func-name-inferrer.cc',
- '../../src/func-name-inferrer.h',
- '../../src/gdb-jit.cc',
- '../../src/gdb-jit.h',
- '../../src/global-handles.cc',
- '../../src/global-handles.h',
- '../../src/globals.h',
- '../../src/handles-inl.h',
- '../../src/handles.cc',
- '../../src/handles.h',
- '../../src/hashmap.h',
- '../../src/heap-inl.h',
- '../../src/heap-profiler.cc',
- '../../src/heap-profiler.h',
- '../../src/heap-snapshot-generator-inl.h',
- '../../src/heap-snapshot-generator.cc',
- '../../src/heap-snapshot-generator.h',
- '../../src/heap.cc',
- '../../src/heap.h',
- '../../src/hydrogen-instructions.cc',
- '../../src/hydrogen-instructions.h',
- '../../src/hydrogen.cc',
- '../../src/hydrogen.h',
- '../../src/ic-inl.h',
- '../../src/ic.cc',
- '../../src/ic.h',
- '../../src/incremental-marking.cc',
- '../../src/incremental-marking.h',
- '../../src/interface.cc',
- '../../src/interface.h',
- '../../src/interpreter-irregexp.cc',
- '../../src/interpreter-irregexp.h',
- '../../src/isolate.cc',
- '../../src/isolate.h',
- '../../src/json-parser.h',
- '../../src/json-stringifier.h',
- '../../src/jsregexp-inl.h',
- '../../src/jsregexp.cc',
- '../../src/jsregexp.h',
- '../../src/lazy-instance.h',
- '../../src/list-inl.h',
- '../../src/list.h',
- '../../src/lithium-allocator-inl.h',
- '../../src/lithium-allocator.cc',
- '../../src/lithium-allocator.h',
- '../../src/lithium.cc',
- '../../src/lithium.h',
- '../../src/liveedit.cc',
- '../../src/liveedit.h',
- '../../src/log-inl.h',
- '../../src/log-utils.cc',
- '../../src/log-utils.h',
- '../../src/log.cc',
- '../../src/log.h',
- '../../src/macro-assembler.h',
- '../../src/mark-compact.cc',
- '../../src/mark-compact.h',
- '../../src/marking-thread.h',
- '../../src/marking-thread.cc',
- '../../src/messages.cc',
- '../../src/messages.h',
- '../../src/natives.h',
- '../../src/objects-debug.cc',
- '../../src/objects-inl.h',
- '../../src/objects-printer.cc',
- '../../src/objects-visiting.cc',
- '../../src/objects-visiting.h',
- '../../src/objects.cc',
- '../../src/objects.h',
- '../../src/once.cc',
- '../../src/once.h',
- '../../src/optimizing-compiler-thread.h',
- '../../src/optimizing-compiler-thread.cc',
- '../../src/parser.cc',
- '../../src/parser.h',
- '../../src/platform-posix.h',
- '../../src/platform-tls-mac.h',
- '../../src/platform-tls-win32.h',
- '../../src/platform-tls.h',
- '../../src/platform.h',
- '../../src/preparse-data-format.h',
- '../../src/preparse-data.cc',
- '../../src/preparse-data.h',
- '../../src/preparser.cc',
- '../../src/preparser.h',
- '../../src/prettyprinter.cc',
- '../../src/prettyprinter.h',
- '../../src/profile-generator-inl.h',
- '../../src/profile-generator.cc',
- '../../src/profile-generator.h',
- '../../src/property-details.h',
- '../../src/property.cc',
- '../../src/property.h',
- '../../src/regexp-macro-assembler-irregexp-inl.h',
- '../../src/regexp-macro-assembler-irregexp.cc',
- '../../src/regexp-macro-assembler-irregexp.h',
- '../../src/regexp-macro-assembler-tracer.cc',
- '../../src/regexp-macro-assembler-tracer.h',
- '../../src/regexp-macro-assembler.cc',
- '../../src/regexp-macro-assembler.h',
- '../../src/regexp-stack.cc',
- '../../src/regexp-stack.h',
- '../../src/rewriter.cc',
- '../../src/rewriter.h',
- '../../src/runtime-profiler.cc',
- '../../src/runtime-profiler.h',
- '../../src/runtime.cc',
- '../../src/runtime.h',
- '../../src/safepoint-table.cc',
- '../../src/safepoint-table.h',
- '../../src/sampler.cc',
- '../../src/sampler.h',
- '../../src/scanner-character-streams.cc',
- '../../src/scanner-character-streams.h',
- '../../src/scanner.cc',
- '../../src/scanner.h',
- '../../src/scopeinfo.cc',
- '../../src/scopeinfo.h',
- '../../src/scopes.cc',
- '../../src/scopes.h',
- '../../src/serialize.cc',
- '../../src/serialize.h',
- '../../src/small-pointer-list.h',
- '../../src/smart-pointers.h',
- '../../src/snapshot-common.cc',
- '../../src/snapshot.h',
- '../../src/spaces-inl.h',
- '../../src/spaces.cc',
- '../../src/spaces.h',
- '../../src/store-buffer-inl.h',
- '../../src/store-buffer.cc',
- '../../src/store-buffer.h',
- '../../src/string-search.cc',
- '../../src/string-search.h',
- '../../src/string-stream.cc',
- '../../src/string-stream.h',
- '../../src/strtod.cc',
- '../../src/strtod.h',
- '../../src/stub-cache.cc',
- '../../src/stub-cache.h',
- '../../src/sweeper-thread.h',
- '../../src/sweeper-thread.cc',
- '../../src/token.cc',
- '../../src/token.h',
- '../../src/transitions-inl.h',
- '../../src/transitions.cc',
- '../../src/transitions.h',
- '../../src/type-info.cc',
- '../../src/type-info.h',
- '../../src/unbound-queue-inl.h',
- '../../src/unbound-queue.h',
- '../../src/unicode-inl.h',
- '../../src/unicode.cc',
- '../../src/unicode.h',
- '../../src/uri.h',
- '../../src/utils-inl.h',
- '../../src/utils.cc',
- '../../src/utils.h',
- '../../src/v8-counters.cc',
- '../../src/v8-counters.h',
- '../../src/v8.cc',
- '../../src/v8.h',
- '../../src/v8checks.h',
- '../../src/v8conversions.cc',
- '../../src/v8conversions.h',
- '../../src/v8globals.h',
- '../../src/v8memory.h',
- '../../src/v8threads.cc',
- '../../src/v8threads.h',
- '../../src/v8utils.cc',
- '../../src/v8utils.h',
- '../../src/variables.cc',
- '../../src/variables.h',
- '../../src/version.cc',
- '../../src/version.h',
- '../../src/vm-state-inl.h',
- '../../src/vm-state.h',
- '../../src/zone-inl.h',
- '../../src/zone.cc',
- '../../src/zone.h',
- ],
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- }, {
- 'toolsets': ['target'],
- }],
- ['v8_target_arch=="arm"', {
- 'sources': [ ### gcmole(arch:arm) ###
- '../../src/arm/assembler-arm-inl.h',
- '../../src/arm/assembler-arm.cc',
- '../../src/arm/assembler-arm.h',
- '../../src/arm/builtins-arm.cc',
- '../../src/arm/code-stubs-arm.cc',
- '../../src/arm/code-stubs-arm.h',
- '../../src/arm/codegen-arm.cc',
- '../../src/arm/codegen-arm.h',
- '../../src/arm/constants-arm.h',
- '../../src/arm/constants-arm.cc',
- '../../src/arm/cpu-arm.cc',
- '../../src/arm/debug-arm.cc',
- '../../src/arm/deoptimizer-arm.cc',
- '../../src/arm/disasm-arm.cc',
- '../../src/arm/frames-arm.cc',
- '../../src/arm/frames-arm.h',
- '../../src/arm/full-codegen-arm.cc',
- '../../src/arm/ic-arm.cc',
- '../../src/arm/lithium-arm.cc',
- '../../src/arm/lithium-arm.h',
- '../../src/arm/lithium-codegen-arm.cc',
- '../../src/arm/lithium-codegen-arm.h',
- '../../src/arm/lithium-gap-resolver-arm.cc',
- '../../src/arm/lithium-gap-resolver-arm.h',
- '../../src/arm/macro-assembler-arm.cc',
- '../../src/arm/macro-assembler-arm.h',
- '../../src/arm/regexp-macro-assembler-arm.cc',
- '../../src/arm/regexp-macro-assembler-arm.h',
- '../../src/arm/simulator-arm.cc',
- '../../src/arm/stub-cache-arm.cc',
- ],
- }],
- ['v8_target_arch=="ia32" or v8_target_arch=="mac" or OS=="mac"', {
- 'sources': [ ### gcmole(arch:ia32) ###
- '../../src/ia32/assembler-ia32-inl.h',
- '../../src/ia32/assembler-ia32.cc',
- '../../src/ia32/assembler-ia32.h',
- '../../src/ia32/builtins-ia32.cc',
- '../../src/ia32/code-stubs-ia32.cc',
- '../../src/ia32/code-stubs-ia32.h',
- '../../src/ia32/codegen-ia32.cc',
- '../../src/ia32/codegen-ia32.h',
- '../../src/ia32/cpu-ia32.cc',
- '../../src/ia32/debug-ia32.cc',
- '../../src/ia32/deoptimizer-ia32.cc',
- '../../src/ia32/disasm-ia32.cc',
- '../../src/ia32/frames-ia32.cc',
- '../../src/ia32/frames-ia32.h',
- '../../src/ia32/full-codegen-ia32.cc',
- '../../src/ia32/ic-ia32.cc',
- '../../src/ia32/lithium-codegen-ia32.cc',
- '../../src/ia32/lithium-codegen-ia32.h',
- '../../src/ia32/lithium-gap-resolver-ia32.cc',
- '../../src/ia32/lithium-gap-resolver-ia32.h',
- '../../src/ia32/lithium-ia32.cc',
- '../../src/ia32/lithium-ia32.h',
- '../../src/ia32/macro-assembler-ia32.cc',
- '../../src/ia32/macro-assembler-ia32.h',
- '../../src/ia32/regexp-macro-assembler-ia32.cc',
- '../../src/ia32/regexp-macro-assembler-ia32.h',
- '../../src/ia32/stub-cache-ia32.cc',
- ],
- }],
- ['v8_target_arch=="mipsel"', {
- 'sources': [ ### gcmole(arch:mipsel) ###
- '../../src/mips/assembler-mips.cc',
- '../../src/mips/assembler-mips.h',
- '../../src/mips/assembler-mips-inl.h',
- '../../src/mips/builtins-mips.cc',
- '../../src/mips/codegen-mips.cc',
- '../../src/mips/codegen-mips.h',
- '../../src/mips/code-stubs-mips.cc',
- '../../src/mips/code-stubs-mips.h',
- '../../src/mips/constants-mips.cc',
- '../../src/mips/constants-mips.h',
- '../../src/mips/cpu-mips.cc',
- '../../src/mips/debug-mips.cc',
- '../../src/mips/deoptimizer-mips.cc',
- '../../src/mips/disasm-mips.cc',
- '../../src/mips/frames-mips.cc',
- '../../src/mips/frames-mips.h',
- '../../src/mips/full-codegen-mips.cc',
- '../../src/mips/ic-mips.cc',
- '../../src/mips/lithium-codegen-mips.cc',
- '../../src/mips/lithium-codegen-mips.h',
- '../../src/mips/lithium-gap-resolver-mips.cc',
- '../../src/mips/lithium-gap-resolver-mips.h',
- '../../src/mips/lithium-mips.cc',
- '../../src/mips/lithium-mips.h',
- '../../src/mips/macro-assembler-mips.cc',
- '../../src/mips/macro-assembler-mips.h',
- '../../src/mips/regexp-macro-assembler-mips.cc',
- '../../src/mips/regexp-macro-assembler-mips.h',
- '../../src/mips/simulator-mips.cc',
- '../../src/mips/stub-cache-mips.cc',
- ],
- }],
- ['v8_target_arch=="x64" or v8_target_arch=="mac" or OS=="mac"', {
- 'sources': [ ### gcmole(arch:x64) ###
- '../../src/x64/assembler-x64-inl.h',
- '../../src/x64/assembler-x64.cc',
- '../../src/x64/assembler-x64.h',
- '../../src/x64/builtins-x64.cc',
- '../../src/x64/code-stubs-x64.cc',
- '../../src/x64/code-stubs-x64.h',
- '../../src/x64/codegen-x64.cc',
- '../../src/x64/codegen-x64.h',
- '../../src/x64/cpu-x64.cc',
- '../../src/x64/debug-x64.cc',
- '../../src/x64/deoptimizer-x64.cc',
- '../../src/x64/disasm-x64.cc',
- '../../src/x64/frames-x64.cc',
- '../../src/x64/frames-x64.h',
- '../../src/x64/full-codegen-x64.cc',
- '../../src/x64/ic-x64.cc',
- '../../src/x64/lithium-codegen-x64.cc',
- '../../src/x64/lithium-codegen-x64.h',
- '../../src/x64/lithium-gap-resolver-x64.cc',
- '../../src/x64/lithium-gap-resolver-x64.h',
- '../../src/x64/lithium-x64.cc',
- '../../src/x64/lithium-x64.h',
- '../../src/x64/macro-assembler-x64.cc',
- '../../src/x64/macro-assembler-x64.h',
- '../../src/x64/regexp-macro-assembler-x64.cc',
- '../../src/x64/regexp-macro-assembler-x64.h',
- '../../src/x64/stub-cache-x64.cc',
- ],
- }],
- ['OS=="linux"', {
- 'link_settings': {
- 'conditions': [
- ['v8_compress_startup_data=="bz2"', {
- 'libraries': [
- '-lbz2',
- ]
- }],
- ],
- },
- 'sources': [ ### gcmole(os:linux) ###
- '../../src/platform-linux.cc',
- '../../src/platform-posix.cc'
- ],
- }
+ 'sources': [ ### gcmole(os:linux) ###
+ '../../src/platform-linux.cc',
+ '../../src/platform-posix.cc'
],
- ['OS=="android"', {
- 'defines': [
- 'CAN_USE_VFP_INSTRUCTIONS',
- ],
- 'sources': [
- '../../src/platform-posix.cc',
- ],
- 'conditions': [
- ['host_os=="mac"', {
- 'target_conditions': [
- ['_toolset=="host"', {
- 'sources': [
- '../../src/platform-macos.cc'
- ]
- }, {
- 'sources': [
- '../../src/platform-linux.cc'
- ]
- }],
- ],
+ }
+ ],
+ ['OS=="android"', {
+ 'defines': [
+ 'CAN_USE_VFP_INSTRUCTIONS',
+ ],
+ 'sources': [
+ '../../src/platform-posix.cc',
+ ],
+ 'conditions': [
+ ['host_os=="mac"', {
+ 'target_conditions': [
+ ['_toolset=="host"', {
+ 'sources': [
+ '../../src/platform-macos.cc'
+ ]
}, {
'sources': [
'../../src/platform-linux.cc'
]
}],
],
- },
- ],
- ['OS=="freebsd"', {
- 'link_settings': {
- 'libraries': [
- '-L/usr/local/lib -lexecinfo',
- ]},
+ }, {
'sources': [
- '../../src/platform-freebsd.cc',
- '../../src/platform-posix.cc'
- ],
- }
+ '../../src/platform-linux.cc'
+ ]
+ }],
],
- ['OS=="openbsd"', {
- 'link_settings': {
- 'libraries': [
- '-L/usr/local/lib -lexecinfo',
- ]},
- 'sources': [
- '../../src/platform-openbsd.cc',
- '../../src/platform-posix.cc'
- ],
- }
+ },
+ ],
+ ['OS=="freebsd"', {
+ 'link_settings': {
+ 'libraries': [
+ '-L/usr/local/lib -lexecinfo',
+ ]},
+ 'sources': [
+ '../../src/platform-freebsd.cc',
+ '../../src/platform-posix.cc'
],
- ['OS=="netbsd"', {
- 'link_settings': {
- 'libraries': [
- '-L/usr/pkg/lib -Wl,-R/usr/pkg/lib -lexecinfo',
- ]},
- 'sources': [
- '../../src/platform-openbsd.cc',
- '../../src/platform-posix.cc'
- ],
- }
+ }
+ ],
+ ['OS=="openbsd"', {
+ 'link_settings': {
+ 'libraries': [
+ '-L/usr/local/lib -lexecinfo',
+ ]},
+ 'sources': [
+ '../../src/platform-openbsd.cc',
+ '../../src/platform-posix.cc'
],
- ['OS=="solaris"', {
- 'link_settings': {
- 'libraries': [
- '-lsocket -lnsl',
- ]},
- 'sources': [
- '../../src/platform-solaris.cc',
- '../../src/platform-posix.cc',
- ],
- }
+ }
+ ],
+ ['OS=="netbsd"', {
+ 'link_settings': {
+ 'libraries': [
+ '-L/usr/pkg/lib -Wl,-R/usr/pkg/lib -lexecinfo',
+ ]},
+ 'sources': [
+ '../../src/platform-openbsd.cc',
+ '../../src/platform-posix.cc'
],
- ['OS=="mac"', {
- 'sources': [
- '../../src/platform-macos.cc',
- '../../src/platform-posix.cc'
- ]},
+ }
+ ],
+ ['OS=="solaris"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lsocket -lnsl',
+ ]},
+ 'sources': [
+ '../../src/platform-solaris.cc',
+ '../../src/platform-posix.cc',
],
- ['OS=="win"', {
+ }
+ ],
+ ['OS=="mac"', {
+ 'sources': [
+ '../../src/platform-macos.cc',
+ '../../src/platform-posix.cc'
+ ]},
+ ],
+ ['OS=="win"', {
+ 'variables': {
+ 'gyp_generators': '<!(echo $GYP_GENERATORS)',
+ },
+ 'conditions': [
+ ['gyp_generators=="make"', {
'variables': {
- 'gyp_generators': '<!(echo $GYP_GENERATORS)',
+ 'build_env': '<!(uname -o)',
},
'conditions': [
- ['gyp_generators=="make"', {
- 'variables': {
- 'build_env': '<!(uname -o)',
- },
- 'conditions': [
- ['build_env=="Cygwin"', {
- 'sources': [
- '../../src/platform-cygwin.cc',
- '../../src/platform-posix.cc',
- ],
- }, {
- 'sources': [
- '../../src/platform-win32.cc',
- '../../src/win32-math.h',
- '../../src/win32-math.cc',
- ],
- }],
+ ['build_env=="Cygwin"', {
+ 'sources': [
+ '../../src/platform-cygwin.cc',
+ '../../src/platform-posix.cc',
],
- 'link_settings': {
- 'libraries': [ '-lwinmm', '-lws2_32' ],
- },
}, {
'sources': [
'../../src/platform-win32.cc',
'../../src/win32-math.h',
'../../src/win32-math.cc',
],
- 'msvs_disabled_warnings': [4351, 4355, 4800],
- 'link_settings': {
- 'libraries': [ '-lwinmm.lib', '-lws2_32.lib' ],
- },
}],
],
- }],
- ['component=="shared_library"', {
- 'defines': [
- 'BUILDING_V8_SHARED',
- 'V8_SHARED',
- ],
- }],
- ['v8_postmortem_support=="true"', {
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc',
- ]
- }],
- ],
- },
- {
- 'target_name': 'js2c',
- 'type': 'none',
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host'],
- }, {
- 'toolsets': ['target'],
- }],
- ],
- 'variables': {
- 'library_files': [
- '../../src/runtime.js',
- '../../src/v8natives.js',
- '../../src/array.js',
- '../../src/string.js',
- '../../src/uri.js',
- '../../src/math.js',
- '../../src/messages.js',
- '../../src/apinatives.js',
- '../../src/debug-debugger.js',
- '../../src/mirror-debugger.js',
- '../../src/liveedit-debugger.js',
- '../../src/date.js',
- '../../src/json.js',
- '../../src/regexp.js',
- '../../src/macros.py',
- ],
- 'experimental_library_files': [
- '../../src/macros.py',
- '../../src/symbol.js',
- '../../src/proxy.js',
- '../../src/collection.js',
- '../../src/object-observe.js',
- '../../src/arraybuffer.js',
- '../../src/typedarray.js',
- '../../src/generator.js'
- ],
- },
- 'actions': [
- {
- 'action_name': 'js2c',
- 'inputs': [
- '../../tools/js2c.py',
- '<@(library_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
- ],
- 'action': [
- 'python',
- '../../tools/js2c.py',
- '<@(_outputs)',
- 'CORE',
- '<(v8_compress_startup_data)',
- '<@(library_files)'
- ],
- },
- {
- 'action_name': 'js2c_experimental',
- 'inputs': [
- '../../tools/js2c.py',
- '<@(experimental_library_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
- ],
- 'action': [
- 'python',
- '../../tools/js2c.py',
- '<@(_outputs)',
- 'EXPERIMENTAL',
- '<(v8_compress_startup_data)',
- '<@(experimental_library_files)'
- ],
- },
- ],
- },
- {
- 'target_name': 'postmortem-metadata',
- 'type': 'none',
- 'variables': {
- 'heapobject_files': [
- '../../src/objects.h',
- '../../src/objects-inl.h',
- ],
- },
- 'actions': [
- {
- 'action_name': 'gen-postmortem-metadata',
- 'inputs': [
- '../../tools/gen-postmortem-metadata.py',
- '<@(heapobject_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc',
- ],
- 'action': [
- 'python',
- '../../tools/gen-postmortem-metadata.py',
- '<@(_outputs)',
- '<@(heapobject_files)'
- ]
- }
- ]
- },
- {
- 'target_name': 'mksnapshot.<(v8_target_arch)',
- 'type': 'executable',
- 'dependencies': [
- 'v8_base.<(v8_target_arch)',
- 'v8_nosnapshot.<(v8_target_arch)',
- ],
- 'include_dirs+': [
- '../../src',
- ],
- 'sources': [
- '../../src/mksnapshot.cc',
- ],
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host'],
- }, {
- 'toolsets': ['target'],
- }],
- ['v8_compress_startup_data=="bz2"', {
- 'libraries': [
- '-lbz2',
- ]
- }],
- ],
- },
- {
- 'target_name': 'v8_shell',
- 'type': 'executable',
- 'dependencies': [
- 'v8'
- ],
- 'sources': [
- '../../samples/shell.cc',
- ],
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host'],
- }, {
- 'toolsets': ['target'],
- }],
- ['OS=="win"', {
- # This could be gotten by not setting chromium_code, if that's OK.
- 'defines': ['_CRT_SECURE_NO_WARNINGS'],
- }],
- ['v8_compress_startup_data=="bz2"', {
- 'libraries': [
- '-lbz2',
- ]
- }],
- ],
- },
- ],
- }, { # use_system_v8 != 0
- 'targets': [
- {
- 'target_name': 'v8',
- 'type': 'none',
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- }, {
- 'toolsets': ['target'],
- }],
- ],
- 'variables': {
- 'shim_headers_path': '<(SHARED_INTERMEDIATE_DIR)/shim_headers/<(_target_name)/<(_toolset)',
- },
- 'include_dirs++': [
- '<(shim_headers_path)',
- ],
- 'all_dependent_settings': {
- 'include_dirs+++': [
- '<(shim_headers_path)',
- ],
- },
- 'actions': [
- {
- 'variables': {
- 'generator_path': '../../../tools/generate_shim_headers/generate_shim_headers.py',
- 'generator_args': [
- '--headers-root', '../../include',
- '--output-directory', '<(shim_headers_path)',
- 'v8-debug.h',
- 'v8-preparser.h',
- 'v8-profiler.h',
- 'v8-testing.h',
- 'v8.h',
- 'v8stdint.h',
- ],
+ 'link_settings': {
+ 'libraries': [ '-lwinmm', '-lws2_32' ],
},
- 'action_name': 'generate_<(_target_name)_shim_headers',
- 'inputs': [
- '<(generator_path)',
- ],
- 'outputs': [
- '<!@pymod_do_main(generate_shim_headers <@(generator_args) --outputs)',
- ],
- 'action': ['python',
- '<(generator_path)',
- '<@(generator_args)',
- '--generate',
- ],
- 'message': 'Generating <(_target_name) shim headers.',
- },
- ],
- 'link_settings': {
- 'libraries': [
- '-lv8',
- ],
- },
- },
- {
- 'target_name': 'v8_shell',
- 'type': 'none',
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host'],
}, {
- 'toolsets': ['target'],
+ 'sources': [
+ '../../src/platform-win32.cc',
+ '../../src/win32-math.h',
+ '../../src/win32-math.cc',
+ ],
+ 'msvs_disabled_warnings': [4351, 4355, 4800],
+ 'link_settings': {
+ 'libraries': [ '-lwinmm.lib', '-lws2_32.lib' ],
+ },
}],
],
- 'dependencies': [
- 'v8'
+ }],
+ ['component=="shared_library"', {
+ 'defines': [
+ 'BUILDING_V8_SHARED',
+ 'V8_SHARED',
+ ],
+ }],
+ ['v8_postmortem_support=="true"', {
+ 'sources': [
+ '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc',
+ ]
+ }],
+ ],
+ },
+ {
+ 'target_name': 'js2c',
+ 'type': 'none',
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ],
+ 'variables': {
+ 'library_files': [
+ '../../src/runtime.js',
+ '../../src/v8natives.js',
+ '../../src/array.js',
+ '../../src/string.js',
+ '../../src/uri.js',
+ '../../src/math.js',
+ '../../src/messages.js',
+ '../../src/apinatives.js',
+ '../../src/debug-debugger.js',
+ '../../src/mirror-debugger.js',
+ '../../src/liveedit-debugger.js',
+ '../../src/date.js',
+ '../../src/json.js',
+ '../../src/regexp.js',
+ '../../src/macros.py',
+ ],
+ 'experimental_library_files': [
+ '../../src/macros.py',
+ '../../src/symbol.js',
+ '../../src/proxy.js',
+ '../../src/collection.js',
+ '../../src/object-observe.js',
+ '../../src/arraybuffer.js',
+ '../../src/typedarray.js',
+ '../../src/generator.js'
+ ],
+ },
+ 'actions': [
+ {
+ 'action_name': 'js2c',
+ 'inputs': [
+ '../../tools/js2c.py',
+ '<@(library_files)',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
+ ],
+ 'action': [
+ 'python',
+ '../../tools/js2c.py',
+ '<@(_outputs)',
+ 'CORE',
+ '<(v8_compress_startup_data)',
+ '<@(library_files)'
+ ],
+ },
+ {
+ 'action_name': 'js2c_experimental',
+ 'inputs': [
+ '../../tools/js2c.py',
+ '<@(experimental_library_files)',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ ],
+ 'action': [
+ 'python',
+ '../../tools/js2c.py',
+ '<@(_outputs)',
+ 'EXPERIMENTAL',
+ '<(v8_compress_startup_data)',
+ '<@(experimental_library_files)'
],
},
],
- }],
+ },
+ {
+ 'target_name': 'postmortem-metadata',
+ 'type': 'none',
+ 'variables': {
+ 'heapobject_files': [
+ '../../src/objects.h',
+ '../../src/objects-inl.h',
+ ],
+ },
+ 'actions': [
+ {
+ 'action_name': 'gen-postmortem-metadata',
+ 'inputs': [
+ '../../tools/gen-postmortem-metadata.py',
+ '<@(heapobject_files)',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc',
+ ],
+ 'action': [
+ 'python',
+ '../../tools/gen-postmortem-metadata.py',
+ '<@(_outputs)',
+ '<@(heapobject_files)'
+ ]
+ }
+ ]
+ },
+ {
+ 'target_name': 'mksnapshot.<(v8_target_arch)',
+ 'type': 'executable',
+ 'dependencies': [
+ 'v8_base.<(v8_target_arch)',
+ 'v8_nosnapshot.<(v8_target_arch)',
+ ],
+ 'include_dirs+': [
+ '../../src',
+ ],
+ 'sources': [
+ '../../src/mksnapshot.cc',
+ ],
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]
+ }],
+ ],
+ },
+ {
+ 'target_name': 'v8_shell',
+ 'type': 'executable',
+ 'dependencies': [
+ 'v8'
+ ],
+ 'sources': [
+ '../../samples/shell.cc',
+ ],
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ['OS=="win"', {
+ # This could be gotten by not setting chromium_code, if that's OK.
+ 'defines': ['_CRT_SECURE_NO_WARNINGS'],
+ }],
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]
+ }],
+ ],
+ },
],
}