Version 3.19.18
Fixed read-only attribute of Function.length in strict mode. (issue 2705)
Fixed Runtime_SetProperty to properly handle OOM failures (Chromium issue 249873)
Emit deprecated check for constant function transitions. (Chromium issue 250609)
Made MathFloorOfDiv optimization trigger more often (Issue 2205)
Make more GCs in idle notification handler. (Chromium issue 241815)
Increased default type info threshold. (Issue 2730)
git-svn-id: http://v8.googlecode.com/svn/trunk@15191 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index a7e0b28..9b1d01c 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -8005,4 +8005,55 @@
}
+v8::Handle<v8::Value> InvokeAccessorGetter(
+ v8::Local<v8::String> property,
+ const v8::AccessorInfo& info,
+ v8::AccessorGetter getter) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+ Address getter_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>(
+ getter));
+ // Leaving JavaScript.
+ VMState<EXTERNAL> state(isolate);
+ ExternalCallbackScope call_scope(isolate, getter_address);
+ return getter(property, info);
+}
+
+
+void InvokeAccessorGetterCallback(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info,
+ v8::AccessorGetterCallback getter) {
+ // Leaving JavaScript.
+ Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+ Address getter_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>(
+ getter));
+ VMState<EXTERNAL> state(isolate);
+ ExternalCallbackScope call_scope(isolate, getter_address);
+ return getter(property, info);
+}
+
+
+v8::Handle<v8::Value> InvokeInvocationCallback(
+ const v8::Arguments& args,
+ v8::InvocationCallback callback) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(args.GetIsolate());
+ Address callback_address =
+ reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback));
+ VMState<EXTERNAL> state(isolate);
+ ExternalCallbackScope call_scope(isolate, callback_address);
+ return callback(args);
+}
+
+
+void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
+ v8::FunctionCallback callback) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+ Address callback_address =
+ reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback));
+ VMState<EXTERNAL> state(isolate);
+ ExternalCallbackScope call_scope(isolate, callback_address);
+ return callback(info);
+}
+
+
} } // namespace v8::internal
diff --git a/src/api.h b/src/api.h
index 3d1c69c..50d4b38 100644
--- a/src/api.h
+++ b/src/api.h
@@ -680,6 +680,24 @@
}
+// Interceptor functions called from generated inline caches to notify
+// CPU profiler that external callbacks are invoked.
+v8::Handle<v8::Value> InvokeAccessorGetter(
+ v8::Local<v8::String> property,
+ const v8::AccessorInfo& info,
+ v8::AccessorGetter getter);
+
+
+void InvokeAccessorGetterCallback(
+ v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info,
+ v8::AccessorGetterCallback getter);
+
+v8::Handle<v8::Value> InvokeInvocationCallback(const v8::Arguments& args,
+ v8::InvocationCallback callback);
+void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
+ v8::FunctionCallback callback);
+
class Testing {
public:
static v8::Testing::StressType stress_type() { return stress_type_; }
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index ee6eb97..ca44ffe 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -6482,13 +6482,6 @@
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
- ExternalReference function) {
- __ mov(r2, Operand(function));
- GenerateCall(masm, r2);
-}
-
-
-void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
Register target) {
intptr_t code =
reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
@@ -7062,10 +7055,10 @@
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : element value to store
- // -- r1 : array literal
- // -- r2 : map of array literal
// -- r3 : element index as smi
- // -- r4 : array literal index in function as smi
+ // -- sp[0] : array literal index in function as smi
+ // -- sp[4] : array literal
+ // clobbers r1, r2, r4
// -----------------------------------
Label element_done;
@@ -7074,6 +7067,11 @@
Label slow_elements;
Label fast_elements;
+ // Get array literal index, array literal and its map.
+ __ ldr(r4, MemOperand(sp, 0 * kPointerSize));
+ __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
+ __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
+
__ CheckFastElements(r2, r5, &double_elements);
// FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
__ JumpIfSmi(r0, &smi_element);
@@ -7348,7 +7346,7 @@
// Get the elements kind and case on that.
__ cmp(r2, Operand(undefined_sentinel));
__ b(eq, &no_info);
- __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+ __ ldr(r3, FieldMemOperand(r2, PropertyCell::kValueOffset));
__ JumpIfNotSmi(r3, &no_info);
__ SmiUntag(r3);
__ jmp(&switch_ready);
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 863848c..1f663f5 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -585,7 +585,6 @@
public:
DirectCEntryStub() {}
void Generate(MacroAssembler* masm);
- void GenerateCall(MacroAssembler* masm, ExternalReference function);
void GenerateCall(MacroAssembler* masm, Register target);
private:
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 468fa77..77d5524 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -361,7 +361,7 @@
ASSERT(back_edge_target->is_bound());
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
__ b(pl, &ok);
@@ -404,7 +404,7 @@
} else if (FLAG_weighted_back_edges) {
int distance = masm_->pc_offset();
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
Label ok;
@@ -1836,13 +1836,14 @@
if (!result_saved) {
__ push(r0);
+ __ Push(Smi::FromInt(expr->literal_index()));
result_saved = true;
}
VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ ldr(r6, MemOperand(sp)); // Copy of array literal.
+ __ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
__ str(result_register(), FieldMemOperand(r1, offset));
// Update the write barrier for the array store.
@@ -1850,10 +1851,7 @@
kLRHasBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
} else {
- __ ldr(r1, MemOperand(sp)); // Copy of array literal.
- __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
__ mov(r3, Operand(Smi::FromInt(i)));
- __ mov(r4, Operand(Smi::FromInt(expr->literal_index())));
StoreArrayLiteralElementStub stub;
__ CallStub(&stub);
}
@@ -1862,6 +1860,7 @@
}
if (result_saved) {
+ __ pop(); // literal index
context()->PlugTOS();
} else {
context()->Plug(r0);
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 87865b2..3d421c1 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1581,8 +1581,8 @@
}
-void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
- StrictModeFlag strict_mode) {
+void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : receiver
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index fbb9c6e..b421f8a 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -929,7 +929,7 @@
BailoutId ast_id = hydrogen_env->ast_id();
ASSERT(!ast_id.IsNone() ||
hydrogen_env->frame_type() != JS_FUNCTION);
- int value_count = hydrogen_env->length();
+ int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
LEnvironment* result = new(zone()) LEnvironment(
hydrogen_env->closure(),
hydrogen_env->frame_type(),
@@ -940,13 +940,15 @@
outer,
hydrogen_env->entry(),
zone());
+ bool needs_arguments_object_materialization = false;
int argument_index = *argument_index_accumulator;
- for (int i = 0; i < value_count; ++i) {
+ for (int i = 0; i < hydrogen_env->length(); ++i) {
if (hydrogen_env->is_special_index(i)) continue;
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
+ needs_arguments_object_materialization = true;
op = NULL;
} else if (value->IsPushArgument()) {
op = new(zone()) LArgument(argument_index++);
@@ -958,6 +960,21 @@
value->CheckFlag(HInstruction::kUint32));
}
+ if (needs_arguments_object_materialization) {
+ HArgumentsObject* arguments = hydrogen_env->entry() == NULL
+ ? graph()->GetArgumentsObject()
+ : hydrogen_env->entry()->arguments_object();
+ ASSERT(arguments->IsLinked());
+ for (int i = 1; i < arguments->arguments_count(); ++i) {
+ HValue* value = arguments->arguments_values()->at(i);
+ ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
+ LOperand* op = UseAny(value);
+ result->AddValue(op,
+ value->representation(),
+ value->CheckFlag(HInstruction::kUint32));
+ }
+ }
+
if (hydrogen_env->frame_type() == JS_FUNCTION) {
*argument_index_accumulator = argument_index;
}
@@ -1386,19 +1403,6 @@
}
-HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
- // A value with an integer representation does not need to be transformed.
- if (dividend->representation().IsInteger32()) {
- return dividend;
- // A change from an integer32 can be replaced by the integer32 value.
- } else if (dividend->IsChange() &&
- HChange::cast(dividend)->from().IsInteger32()) {
- return HChange::cast(dividend)->value();
- }
- return NULL;
-}
-
-
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
if (CpuFeatures::IsSupported(SUDIV)) {
// A value with an integer representation does not need to be transformed.
@@ -2588,8 +2592,9 @@
undefined,
instr->inlining_kind(),
instr->undefined_receiver());
- if (instr->arguments_var() != NULL) {
- inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
+ // Only replay binding of arguments object if it wasn't removed from graph.
+ if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
+ inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index ccfd0db..8eff338 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -2692,7 +2692,6 @@
LInstruction* DoRSub(HSub* instr);
static bool HasMagicNumberForDivisor(int32_t divisor);
- static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
LInstruction* DoMathFloor(HUnaryMathOperation* instr);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 5acf360..ef860e0 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -580,27 +580,15 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* pushed_arguments_index,
- int* pushed_arguments_count) {
+ Translation* translation) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
- int translation_size = environment->values()->length();
+ int translation_size = environment->translation_size();
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- // Function parameters are arguments to the outermost environment. The
- // arguments index points to the first element of a sequence of tagged
- // values on the stack that represent the arguments. This needs to be
- // kept in sync with the LArgumentsElements implementation.
- *pushed_arguments_index = -environment->parameter_count();
- *pushed_arguments_count = environment->parameter_count();
-
- WriteTranslation(environment->outer(),
- translation,
- pushed_arguments_index,
- pushed_arguments_count);
+ WriteTranslation(environment->outer(), translation);
bool has_closure_id = !info()->closure().is_null() &&
!info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
@@ -632,23 +620,6 @@
break;
}
- // Inlined frames which push their arguments cause the index to be
- // bumped and another stack area to be used for materialization,
- // otherwise actual argument values are unknown for inlined frames.
- bool arguments_known = true;
- int arguments_index = *pushed_arguments_index;
- int arguments_count = *pushed_arguments_count;
- if (environment->entry() != NULL) {
- arguments_known = environment->entry()->arguments_pushed();
- arguments_index = arguments_index < 0
- ? GetStackSlotCount() : arguments_index + arguments_count;
- arguments_count = environment->entry()->arguments_count() + 1;
- if (environment->entry()->arguments_pushed()) {
- *pushed_arguments_index = arguments_index;
- *pushed_arguments_count = arguments_count;
- }
- }
-
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -660,10 +631,7 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
@@ -672,20 +640,36 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false,
- arguments_known,
- arguments_index,
- arguments_count);
+ false);
}
}
+ // TODO(mstarzinger): Introduce marker operands to indicate that this value
+ // is not present and must be reconstructed from the deoptimizer. Currently
+ // this is only used for the arguments object.
+ if (value == NULL) {
+ int arguments_count = environment->values()->length() - translation_size;
+ translation->BeginArgumentsObject(arguments_count);
+ for (int i = 0; i < arguments_count; ++i) {
+ LOperand* value = environment->values()->at(translation_size + i);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsRegister() ||
+ environment->spilled_registers()[value->index()] == NULL);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsDoubleRegister() ||
+ environment->spilled_double_registers()[value->index()] == NULL);
+ AddToTranslation(translation,
+ value,
+ environment->HasTaggedValueAt(translation_size + i),
+ environment->HasUint32ValueAt(translation_size + i));
+ }
+ continue;
+ }
+
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
}
}
@@ -693,17 +677,8 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count) {
- if (op == NULL) {
- // TODO(twuerthinger): Introduce marker operands to indicate that this value
- // is not present and must be reconstructed from the deoptimizer. Currently
- // this is only used for the arguments object.
- translation->StoreArgumentsObject(
- arguments_known, arguments_index, arguments_count);
- } else if (op->IsStackSlot()) {
+ bool is_uint32) {
+ if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else if (is_uint32) {
@@ -810,8 +785,6 @@
int frame_count = 0;
int jsframe_count = 0;
- int args_index = 0;
- int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@@ -819,7 +792,7 @@
}
}
Translation translation(&translations_, frame_count, jsframe_count, zone());
- WriteTranslation(environment, &translation, &args_index, &args_count);
+ WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
@@ -2791,7 +2764,7 @@
PredictableCodeSizeScope predictable(masm_, 5 * Assembler::kInstrSize);
Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
__ mov(ip, Operand(Handle<Object>(cell)));
- __ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
+ __ ldr(ip, FieldMemOperand(ip, PropertyCell::kValueOffset));
__ cmp(map, Operand(ip));
__ b(ne, &cache_miss);
// We use Factory::the_hole_value() on purpose instead of loading from the
@@ -5280,7 +5253,7 @@
AllowDeferredHandleDereference smi_check;
if (isolate()->heap()->InNewSpace(*target)) {
Register reg = ToRegister(instr->value());
- Handle<Cell> cell = isolate()->factory()->NewJSGlobalPropertyCell(target);
+ Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target);
__ mov(ip, Operand(Handle<Object>(cell)));
__ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset));
__ cmp(reg, ip);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index cecf152..aeba5ea 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -171,10 +171,7 @@
int additional_offset);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* arguments_index,
- int* arguments_count);
+ void WriteTranslation(LEnvironment* environment, Translation* translation);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -293,10 +290,7 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count);
+ bool is_uint32);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 4b6eac2..81a2d37 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -2244,6 +2244,9 @@
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
+ Address function_address,
+ ExternalReference thunk_ref,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset) {
@@ -2274,11 +2277,31 @@
PopSafepointRegisters();
}
+ ASSERT(!thunk_last_arg.is(r3));
+ Label profiler_disabled;
+ Label end_profiler_check;
+ bool* is_profiling_flag =
+ isolate()->cpu_profiler()->is_profiling_address();
+ STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+ mov(r3, Operand(reinterpret_cast<int32_t>(is_profiling_flag)));
+ ldrb(r3, MemOperand(r3, 0));
+ cmp(r3, Operand(0));
+ b(eq, &profiler_disabled);
+
+ // Additional parameter is the address of the actual callback.
+ mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(function_address)));
+ mov(r3, Operand(thunk_ref));
+ jmp(&end_profiler_check);
+
+ bind(&profiler_disabled);
+ mov(r3, Operand(function));
+ bind(&end_profiler_check);
+
// Native call returns to the DirectCEntry stub which redirects to the
// return address pushed on stack (could have moved after GC).
// DirectCEntry stub itself is generated early and never moves.
DirectCEntryStub stub;
- stub.GenerateCall(this, function);
+ stub.GenerateCall(this, r3);
if (FLAG_log_timer_events) {
FrameScope frame(this, StackFrame::MANUAL);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 11d3066..8d3626d 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -1085,6 +1085,9 @@
// - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function,
+ Address function_address,
+ ExternalReference thunk_ref,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_fp);
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index c9db167..a29d461 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -830,7 +830,10 @@
Isolate* isolate = Isolate::Current();
Redirection* current = isolate->simulator_redirection();
for (; current != NULL; current = current->next_) {
- if (current->external_function_ == external_function) return current;
+ if (current->external_function_ == external_function) {
+ ASSERT_EQ(current->type(), type);
+ return current;
+ }
}
return new Redirection(external_function, type);
}
@@ -1629,12 +1632,19 @@
// (refer to InvocationCallback in v8.h).
typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)(
+ int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1);
// This signature supports direct call to accessor getter callback.
typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
int32_t arg1);
typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0,
int32_t arg1);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)(
+ int32_t arg0, int32_t arg1, int32_t arg2);
+typedef void (*SimulatorRuntimeProfilingGetterCallNew)(
+ int32_t arg0, int32_t arg1, int32_t arg2);
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime.
@@ -1799,6 +1809,31 @@
target(arg0);
}
} else if (
+ redirection->type() == ExternalReference::PROFILING_API_CALL ||
+ redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) {
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+ PrintF("Call to host function at %p args %08x %08x",
+ reinterpret_cast<void*>(external), arg0, arg1);
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
+ }
+ CHECK(stack_aligned);
+ if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
+ SimulatorRuntimeProfilingApiCall target =
+ reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+ v8::Handle<v8::Value> result = target(arg0, arg1);
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
+ }
+ set_register(r0, reinterpret_cast<int32_t>(*result));
+ } else {
+ SimulatorRuntimeProfilingApiCallNew target =
+ reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external);
+ target(arg0, arg1);
+ }
+ } else if (
redirection->type() == ExternalReference::DIRECT_GETTER_CALL ||
redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) {
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
@@ -1823,6 +1858,32 @@
reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external);
target(arg0, arg1);
}
+ } else if (
+ redirection->type() == ExternalReference::PROFILING_GETTER_CALL ||
+ redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) {
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+ PrintF("Call to host function at %p args %08x %08x %08x",
+ reinterpret_cast<void*>(external), arg0, arg1, arg2);
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
+ }
+ CHECK(stack_aligned);
+ if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
+ SimulatorRuntimeProfilingGetterCall target =
+ reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
+ v8::Handle<v8::Value> result = target(arg0, arg1, arg2);
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
+ }
+ set_register(r0, reinterpret_cast<int32_t>(*result));
+ } else {
+ SimulatorRuntimeProfilingGetterCallNew target =
+ reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>(
+ external);
+ target(arg0, arg1, arg2);
+ }
} else {
// builtin call.
ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
@@ -1830,7 +1891,7 @@
reinterpret_cast<SimulatorRuntimeCall>(external);
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
- "Call to host function at %p"
+ "Call to host function at %p "
"args %08x, %08x, %08x, %08x, %08x, %08x",
FUNCTION_ADDR(target),
arg0,
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 1ccc106..decfa74 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -512,7 +512,13 @@
Register storage_reg = name_reg;
- if (FLAG_track_fields && representation.IsSmi()) {
+ if (details.type() == CONSTANT_FUNCTION) {
+ Handle<HeapObject> constant(
+ HeapObject::cast(descriptors->GetValue(descriptor)));
+ __ LoadHeapObject(scratch1, constant);
+ __ cmp(value_reg, scratch1);
+ __ b(ne, miss_restore_name);
+ } else if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
@@ -541,7 +547,8 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (object->map()->unused_property_fields() == 0) {
+ if (details.type() == FIELD &&
+ object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@@ -570,6 +577,12 @@
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ if (details.type() == CONSTANT_FUNCTION) {
+ ASSERT(value_reg.is(r0));
+ __ Ret();
+ return;
+ }
+
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
@@ -956,8 +969,22 @@
ExternalReference ref = ExternalReference(&fun,
type,
masm->isolate());
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeInvocationCallback)
+ : FUNCTION_ADDR(&InvokeFunctionCallback);
+ ExternalReference::Type thunk_type =
+ returns_handle ?
+ ExternalReference::PROFILING_API_CALL :
+ ExternalReference::PROFILING_API_CALL_NEW;
+ ApiFunction thunk_fun(thunk_address);
+ ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+ masm->isolate());
+
AllowExternalCallThatCantCauseGC scope(masm);
__ CallApiFunctionAndReturn(ref,
+ function_address,
+ thunk_ref,
+ r1,
kStackUnwindSpace,
returns_handle,
kFastApiCallArguments + 1);
@@ -1454,14 +1481,28 @@
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
!CallbackTable::ReturnsVoid(isolate(), getter_address);
+
ApiFunction fun(getter_address);
ExternalReference::Type type =
returns_handle ?
ExternalReference::DIRECT_GETTER_CALL :
ExternalReference::DIRECT_GETTER_CALL_NEW;
-
ExternalReference ref = ExternalReference(&fun, type, isolate());
+
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeAccessorGetter)
+ : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+ ExternalReference::Type thunk_type =
+ returns_handle ?
+ ExternalReference::PROFILING_GETTER_CALL :
+ ExternalReference::PROFILING_GETTER_CALL_NEW;
+ ApiFunction thunk_fun(thunk_address);
+ ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+ isolate());
__ CallApiFunctionAndReturn(ref,
+ getter_address,
+ thunk_ref,
+ r2,
kStackUnwindSpace,
returns_handle,
5);
@@ -2669,7 +2710,7 @@
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
// ----------- S t a t e -------------
@@ -2842,7 +2883,7 @@
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name) {
Label miss;
@@ -2986,7 +3027,7 @@
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<GlobalObject> global,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
diff --git a/src/assembler.h b/src/assembler.h
index f66f8bf..95853e8 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -647,17 +647,35 @@
// Handle<Value> f(v8::Arguments&)
DIRECT_API_CALL,
+ // Call to invocation callback via InvokeInvocationCallback.
+ // Handle<Value> f(v8::Arguments&, v8::InvocationCallback)
+ PROFILING_API_CALL,
+
// Direct call to API function callback.
// void f(v8::Arguments&)
DIRECT_API_CALL_NEW,
+ // Call to function callback via InvokeFunctionCallback.
+ // void f(v8::Arguments&, v8::FunctionCallback)
+ PROFILING_API_CALL_NEW,
+
// Direct call to accessor getter callback.
// Handle<value> f(Local<String> property, AccessorInfo& info)
DIRECT_GETTER_CALL,
+ // Call to accessor getter callback via InvokeAccessorGetter.
+ // Handle<value> f(Local<String> property, AccessorInfo& info,
+ // AccessorGetter getter)
+ PROFILING_GETTER_CALL,
+
// Direct call to accessor getter callback.
// void f(Local<String> property, AccessorInfo& info)
- DIRECT_GETTER_CALL_NEW
+ DIRECT_GETTER_CALL_NEW,
+
+ // Call to accessor getter callback via InvokeAccessorGetterCallback.
+ // void f(Local<String> property, AccessorInfo& info,
+ // AccessorGetterCallback callback)
+ PROFILING_GETTER_CALL_NEW
};
static void SetUp();
diff --git a/src/ast.cc b/src/ast.cc
index 0ebbd35..bf607d2 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -663,12 +663,13 @@
void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- type_ = oracle->UnaryType(this);
+ type_ = oracle->UnaryType(UnaryOperationFeedbackId());
}
void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- oracle->BinaryType(this, &left_type_, &right_type_, &result_type_,
+ oracle->BinaryType(BinaryOperationFeedbackId(),
+ &left_type_, &right_type_, &result_type_,
&has_fixed_right_arg_, &fixed_right_arg_value_);
}
diff --git a/src/ast.h b/src/ast.h
index b7ada60..b07456b 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1837,7 +1837,7 @@
TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- TypeInfo type() const { return type_; }
+ Handle<Type> type() const { return type_; }
protected:
UnaryOperation(Isolate* isolate,
@@ -1858,7 +1858,7 @@
Expression* expression_;
int pos_;
- TypeInfo type_;
+ Handle<Type> type_;
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
@@ -1882,9 +1882,9 @@
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- TypeInfo left_type() const { return left_type_; }
- TypeInfo right_type() const { return right_type_; }
- TypeInfo result_type() const { return result_type_; }
+ Handle<Type> left_type() const { return left_type_; }
+ Handle<Type> right_type() const { return right_type_; }
+ Handle<Type> result_type() const { return result_type_; }
bool has_fixed_right_arg() const { return has_fixed_right_arg_; }
int fixed_right_arg_value() const { return fixed_right_arg_value_; }
@@ -1909,9 +1909,9 @@
Expression* right_;
int pos_;
- TypeInfo left_type_;
- TypeInfo right_type_;
- TypeInfo result_type_;
+ Handle<Type> left_type_;
+ Handle<Type> right_type_;
+ Handle<Type> result_type_;
bool has_fixed_right_arg_;
int fixed_right_arg_value_;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0b39faa..c78bf9c 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -538,31 +538,33 @@
if (prototypeMode != DONT_ADD_PROTOTYPE) {
prototype = factory()->NewForeign(&Accessors::FunctionPrototype);
}
- PropertyAttributes attribs = static_cast<PropertyAttributes>(
- DONT_ENUM | DONT_DELETE);
+ PropertyAttributes rw_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+ PropertyAttributes ro_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
map->set_instance_descriptors(*descriptors);
{ // Add length.
- CallbacksDescriptor d(*factory()->length_string(), *length, attribs);
+ CallbacksDescriptor d(*factory()->length_string(), *length, ro_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add name.
- CallbacksDescriptor d(*factory()->name_string(), *name, attribs);
+ CallbacksDescriptor d(*factory()->name_string(), *name, rw_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
- CallbacksDescriptor d(*factory()->arguments_string(), *arguments, attribs);
+ CallbacksDescriptor d(*factory()->arguments_string(), *arguments,
+ rw_attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add caller.
- CallbacksDescriptor d(*factory()->caller_string(), *caller, attribs);
+ CallbacksDescriptor d(*factory()->caller_string(), *caller, rw_attribs);
map->AppendDescriptor(&d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
// Add prototype.
- if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
- attribs = static_cast<PropertyAttributes>(attribs | READ_ONLY);
- }
+ PropertyAttributes attribs =
+ prototypeMode == ADD_WRITEABLE_PROTOTYPE ? rw_attribs : ro_attribs;
CallbacksDescriptor d(*factory()->prototype_string(), *prototype, attribs);
map->AppendDescriptor(&d, witness);
}
@@ -2500,8 +2502,8 @@
Handle<Object> value = Handle<Object>(properties->ValueAt(i),
isolate());
ASSERT(!value->IsCell());
- if (value->IsJSGlobalPropertyCell()) {
- value = Handle<Object>(JSGlobalPropertyCell::cast(*value)->value(),
+ if (value->IsPropertyCell()) {
+ value = Handle<Object>(PropertyCell::cast(*value)->value(),
isolate());
}
PropertyDetails details = properties->DetailsAt(i);
diff --git a/src/builtins.cc b/src/builtins.cc
index d97a477..fd7dd8a 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1496,12 +1496,12 @@
static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
- StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
+ StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
}
static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
- StoreIC::GenerateGlobalProxy(masm, kStrictMode);
+ StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
}
@@ -1510,6 +1510,16 @@
}
+static void Generate_StoreIC_Generic(MacroAssembler* masm) {
+ StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
+}
+
+
+static void Generate_StoreIC_Generic_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
+}
+
+
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
}
diff --git a/src/builtins.h b/src/builtins.h
index c45fbfd..df833df 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -166,6 +166,10 @@
Code::kNoExtraICState) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
+ V(StoreIC_Generic, STORE_IC, GENERIC, \
+ Code::kNoExtraICState) \
+ V(StoreIC_Generic_Strict, STORE_IC, GENERIC, \
+ kStrictMode) \
V(StoreIC_GlobalProxy, STORE_IC, GENERIC, \
Code::kNoExtraICState) \
V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index e1e25fb..11cd307 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -144,7 +144,7 @@
set_current_block(next_block);
HConstant* undefined_constant = new(zone) HConstant(
- isolate()->factory()->undefined_value(), Representation::Tagged());
+ isolate()->factory()->undefined_value());
AddInstruction(undefined_constant);
graph()->set_undefined_constant(undefined_constant);
@@ -196,8 +196,7 @@
stack_pop_count->ClearFlag(HValue::kCanOverflow);
} else {
int count = descriptor_->hint_stack_parameter_count_;
- stack_pop_count = AddInstruction(new(zone)
- HConstant(count, Representation::Integer32()));
+ stack_pop_count = AddInstruction(new(zone) HConstant(count));
}
}
@@ -391,13 +390,11 @@
HValue* boilerplate_size =
AddInstruction(new(zone) HInstanceSize(boilerplate));
HValue* size_in_words =
- AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2,
- Representation::Integer32()));
+ AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
checker.IfCompare(boilerplate_size, size_in_words, Token::EQ);
checker.Then();
- HValue* size_in_bytes =
- AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
+ HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
if (isolate()->heap()->ShouldGloballyPretenure()) {
flags = static_cast<HAllocate::Flags>(
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 2f8479f..455c893 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -248,6 +248,9 @@
void SharedFunctionInfoMoveEvent(Address from, Address to);
INLINE(bool is_profiling() const) { return is_profiling_; }
+ bool* is_profiling_address() {
+ return &is_profiling_;
+ }
private:
void StartProcessorIfNotStarted();
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index 5226364..298518d 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -150,18 +150,19 @@
static Persistent<Array> current_completions;
Isolate* isolate = read_line_editor.isolate_;
Locker lock(isolate);
+ HandleScope scope;
+ Handle<Array> completions;
if (state == 0) {
- HandleScope scope;
Local<String> full_text = String::New(rl_line_buffer, rl_point);
- Handle<Array> completions =
- Shell::GetCompletions(isolate, String::New(text), full_text);
- current_completions = Persistent<Array>::New(isolate, completions);
+ completions = Shell::GetCompletions(isolate, String::New(text), full_text);
+ current_completions.Reset(isolate, completions);
current_index = 0;
+ } else {
+ completions = Local<Array>::New(isolate, current_completions);
}
- if (current_index < current_completions->Length()) {
- HandleScope scope;
+ if (current_index < completions->Length()) {
Handle<Integer> index = Integer::New(current_index);
- Handle<Value> str_obj = current_completions->Get(index);
+ Handle<Value> str_obj = completions->Get(index);
current_index++;
String::Utf8Value str(str_obj);
return strdup(*str);
diff --git a/src/data-flow.h b/src/data-flow.h
index 7eeb794..8ceccf6 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -215,6 +215,8 @@
};
GrowableBitVector() : bits_(NULL) { }
+ GrowableBitVector(int length, Zone* zone)
+ : bits_(new(zone) BitVector(length, zone)) { }
bool Contains(int value) const {
if (!InBitsRange(value)) return false;
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 723d3f6..14c1d73 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -534,8 +534,9 @@
output_count_(0),
jsframe_count_(0),
output_(NULL),
- deferred_arguments_objects_values_(0),
- deferred_arguments_objects_(0),
+ deferred_objects_tagged_values_(0),
+ deferred_objects_double_values_(0),
+ deferred_objects_(0),
deferred_heap_numbers_(0),
trace_(false) {
// For COMPILED_STUBs called from builtins, the function pointer is a SMI
@@ -1566,15 +1567,14 @@
void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ASSERT_NE(DEBUGGER, bailout_type_);
- // Handlify all argument object values before triggering any allocation.
- List<Handle<Object> > values(deferred_arguments_objects_values_.length());
- for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
- values.Add(Handle<Object>(deferred_arguments_objects_values_[i],
- isolate_));
+ // Handlify all tagged object values before triggering any allocation.
+ List<Handle<Object> > values(deferred_objects_tagged_values_.length());
+ for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
+ values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
}
// Play it safe and clear all unhandlified values before we continue.
- deferred_arguments_objects_values_.Clear();
+ deferred_objects_tagged_values_.Clear();
// Materialize all heap numbers before looking at arguments because when the
// output frames are used to materialize arguments objects later on they need
@@ -1591,6 +1591,18 @@
Memory::Object_at(d.slot_address()) = *num;
}
+ // Materialize all heap numbers required for arguments objects.
+ for (int i = 0; i < values.length(); i++) {
+ if (!values.at(i)->IsTheHole()) continue;
+ double double_value = deferred_objects_double_values_[i];
+ Handle<Object> num = isolate_->factory()->NewNumber(double_value);
+ if (trace_) {
+ PrintF("Materializing a new heap number %p [%e] for arguments object\n",
+ reinterpret_cast<void*>(*num), double_value);
+ }
+ values.Set(i, num);
+ }
+
// Materialize arguments objects one frame at a time.
for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
if (frame_index != 0) it->Advance();
@@ -1599,9 +1611,9 @@
Handle<JSObject> arguments;
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
- ArgumentsObjectMaterializationDescriptor descriptor =
- deferred_arguments_objects_.RemoveLast();
- const int length = descriptor.arguments_length();
+ ObjectMaterializationDescriptor descriptor =
+ deferred_objects_.RemoveLast();
+ const int length = descriptor.object_length();
if (arguments.is_null()) {
if (frame->has_adapted_arguments()) {
// Use the arguments adapter frame we just built to materialize the
@@ -1695,7 +1707,7 @@
#endif
-static const char* TraceValueType(bool is_smi, bool is_native) {
+static const char* TraceValueType(bool is_smi, bool is_native = false) {
if (is_native) {
return "native";
} else if (is_smi) {
@@ -1706,6 +1718,204 @@
}
+void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
+ int object_opcode,
+ int field_index) {
+ disasm::NameConverter converter;
+ Address object_slot = deferred_objects_.last().slot_address();
+
+ // Ignore commands marked as duplicate and act on the first non-duplicate.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ while (opcode == Translation::DUPLICATE) {
+ opcode = static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+ opcode = static_cast<Translation::Opcode>(iterator->Next());
+ }
+
+ switch (opcode) {
+ case Translation::BEGIN:
+ case Translation::JS_FRAME:
+ case Translation::ARGUMENTS_ADAPTOR_FRAME:
+ case Translation::CONSTRUCT_STUB_FRAME:
+ case Translation::GETTER_STUB_FRAME:
+ case Translation::SETTER_STUB_FRAME:
+ case Translation::COMPILED_STUB_FRAME:
+ case Translation::ARGUMENTS_OBJECT:
+ case Translation::DUPLICATE:
+ UNREACHABLE();
+ return;
+
+ case Translation::REGISTER: {
+ int input_reg = iterator->Next();
+ intptr_t input_value = input_->GetRegister(input_reg);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("0x%08" V8PRIxPTR " ; %s ", input_value,
+ converter.NameOfCPURegister(input_reg));
+ reinterpret_cast<Object*>(input_value)->ShortPrint();
+ PrintF("\n");
+ }
+ AddObjectTaggedValue(input_value);
+ return;
+ }
+
+ case Translation::INT32_REGISTER: {
+ int input_reg = iterator->Next();
+ intptr_t value = input_->GetRegister(input_reg);
+ bool is_smi = Smi::IsValid(value);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%" V8PRIdPTR " ; %s (%s)\n", value,
+ converter.NameOfCPURegister(input_reg),
+ TraceValueType(is_smi));
+ }
+ if (is_smi) {
+ intptr_t tagged_value =
+ reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+ AddObjectTaggedValue(tagged_value);
+ } else {
+ double double_value = static_cast<double>(static_cast<int32_t>(value));
+ AddObjectDoubleValue(double_value);
+ }
+ return;
+ }
+
+ case Translation::UINT32_REGISTER: {
+ int input_reg = iterator->Next();
+ uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
+ bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%" V8PRIdPTR " ; uint %s (%s)\n", value,
+ converter.NameOfCPURegister(input_reg),
+ TraceValueType(is_smi));
+ }
+ if (is_smi) {
+ intptr_t tagged_value =
+ reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+ AddObjectTaggedValue(tagged_value);
+ } else {
+ double double_value = static_cast<double>(static_cast<uint32_t>(value));
+ AddObjectDoubleValue(double_value);
+ }
+ return;
+ }
+
+ case Translation::DOUBLE_REGISTER: {
+ int input_reg = iterator->Next();
+ double value = input_->GetDoubleRegister(input_reg);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%e ; %s\n", value,
+ DoubleRegister::AllocationIndexToString(input_reg));
+ }
+ AddObjectDoubleValue(value);
+ return;
+ }
+
+ case Translation::STACK_SLOT: {
+ int input_slot_index = iterator->Next();
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
+ intptr_t input_value = input_->GetFrameSlot(input_offset);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
+ reinterpret_cast<Object*>(input_value)->ShortPrint();
+ PrintF("\n");
+ }
+ AddObjectTaggedValue(input_value);
+ return;
+ }
+
+ case Translation::INT32_STACK_SLOT: {
+ int input_slot_index = iterator->Next();
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
+ intptr_t value = input_->GetFrameSlot(input_offset);
+ bool is_smi = Smi::IsValid(value);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%" V8PRIdPTR " ; [sp + %d] (%s)\n",
+ value, input_offset, TraceValueType(is_smi));
+ }
+ if (is_smi) {
+ intptr_t tagged_value =
+ reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+ AddObjectTaggedValue(tagged_value);
+ } else {
+ double double_value = static_cast<double>(static_cast<int32_t>(value));
+ AddObjectDoubleValue(double_value);
+ }
+ return;
+ }
+
+ case Translation::UINT32_STACK_SLOT: {
+ int input_slot_index = iterator->Next();
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
+ uintptr_t value =
+ static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
+ bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
+ value, input_offset, TraceValueType(is_smi));
+ }
+ if (is_smi) {
+ intptr_t tagged_value =
+ reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+ AddObjectTaggedValue(tagged_value);
+ } else {
+ double double_value = static_cast<double>(static_cast<uint32_t>(value));
+ AddObjectDoubleValue(double_value);
+ }
+ return;
+ }
+
+ case Translation::DOUBLE_STACK_SLOT: {
+ int input_slot_index = iterator->Next();
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
+ double value = input_->GetDoubleFrameSlot(input_offset);
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ PrintF("%e ; [sp + %d]\n", value, input_offset);
+ }
+ AddObjectDoubleValue(value);
+ return;
+ }
+
+ case Translation::LITERAL: {
+ Object* literal = ComputeLiteral(iterator->Next());
+ if (trace_) {
+ PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
+ reinterpret_cast<intptr_t>(object_slot),
+ field_index);
+ literal->ShortPrint();
+ PrintF(" ; literal\n");
+ }
+ intptr_t value = reinterpret_cast<intptr_t>(literal);
+ AddObjectTaggedValue(value);
+ return;
+ }
+ }
+}
+
+
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int frame_index,
unsigned output_offset,
@@ -1758,7 +1968,6 @@
intptr_t value = input_->GetRegister(input_reg);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
-
if (trace_) {
PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
@@ -1836,8 +2045,7 @@
case Translation::STACK_SLOT: {
int input_slot_index = iterator->Next();
- unsigned input_offset =
- input_->GetOffsetFromSlotIndex(input_slot_index);
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t input_value = input_->GetFrameSlot(input_offset);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": ",
@@ -1855,8 +2063,7 @@
case Translation::INT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
- unsigned input_offset =
- input_->GetOffsetFromSlotIndex(input_slot_index);
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
Smi::IsValid(value);
@@ -1888,8 +2095,7 @@
case Translation::UINT32_STACK_SLOT: {
int input_slot_index = iterator->Next();
- unsigned input_offset =
- input_->GetOffsetFromSlotIndex(input_slot_index);
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
@@ -1922,8 +2128,7 @@
case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator->Next();
- unsigned input_offset =
- input_->GetOffsetFromSlotIndex(input_slot_index);
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
@@ -1954,31 +2159,24 @@
}
case Translation::ARGUMENTS_OBJECT: {
- bool args_known = iterator->Next();
- int args_index = iterator->Next() + 1; // Skip receiver.
- int args_length = iterator->Next() - 1; // Skip receiver.
+ int length = iterator->Next();
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
isolate_->heap()->arguments_marker()->ShortPrint();
- PrintF(" ; %sarguments object\n", args_known ? "" : "dummy ");
+ PrintF(" ; arguments object (length = %d)\n", length);
}
// Use the arguments marker value as a sentinel and fill in the arguments
// object after the deoptimized frame is built.
intptr_t value = reinterpret_cast<intptr_t>(
isolate_->heap()->arguments_marker());
- AddArgumentsObject(
- output_[frame_index]->GetTop() + output_offset, args_length);
+ AddObjectStart(output_[frame_index]->GetTop() + output_offset, length);
output_[frame_index]->SetFrameSlot(output_offset, value);
- // We save the tagged argument values on the side and materialize the
- // actual arguments object after the deoptimized frame is built.
- for (int i = 0; i < args_length; i++) {
- unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i);
- intptr_t input_value = args_known
- ? input_->GetFrameSlot(input_offset)
- : reinterpret_cast<intptr_t>(isolate_->heap()->the_hole_value());
- AddArgumentsObjectValue(input_value);
+ // We save the argument values on the side and materialize the actual
+ // arguments object after the deoptimized frame is built.
+ for (int i = 0; i < length; i++) {
+ DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i);
}
return;
}
@@ -2324,15 +2522,22 @@
}
-void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
- ArgumentsObjectMaterializationDescriptor object_desc(
- reinterpret_cast<Address>(slot_address), argc);
- deferred_arguments_objects_.Add(object_desc);
+void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) {
+ ObjectMaterializationDescriptor object_desc(
+ reinterpret_cast<Address>(slot_address), length);
+ deferred_objects_.Add(object_desc);
}
-void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
- deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
+void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
+ deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
+ deferred_objects_double_values_.Add(isolate()->heap()->nan_value()->value());
+}
+
+
+void Deoptimizer::AddObjectDoubleValue(double value) {
+ deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
+ deferred_objects_double_values_.Add(value);
}
@@ -2556,6 +2761,12 @@
}
+void Translation::BeginArgumentsObject(int args_length) {
+ buffer_->Add(ARGUMENTS_OBJECT, zone());
+ buffer_->Add(args_length, zone());
+}
+
+
void Translation::StoreRegister(Register reg) {
buffer_->Add(REGISTER, zone());
buffer_->Add(reg.code(), zone());
@@ -2610,16 +2821,6 @@
}
-void Translation::StoreArgumentsObject(bool args_known,
- int args_index,
- int args_length) {
- buffer_->Add(ARGUMENTS_OBJECT, zone());
- buffer_->Add(args_known, zone());
- buffer_->Add(args_index, zone());
- buffer_->Add(args_length, zone());
-}
-
-
void Translation::MarkDuplicate() {
buffer_->Add(DUPLICATE, zone());
}
@@ -2631,6 +2832,7 @@
return 0;
case GETTER_STUB_FRAME:
case SETTER_STUB_FRAME:
+ case ARGUMENTS_OBJECT:
case REGISTER:
case INT32_REGISTER:
case UINT32_REGISTER:
@@ -2647,7 +2849,6 @@
case CONSTRUCT_STUB_FRAME:
return 2;
case JS_FRAME:
- case ARGUMENTS_OBJECT:
return 3;
}
UNREACHABLE();
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 5569f7f..5ca635c 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -75,17 +75,17 @@
};
-class ArgumentsObjectMaterializationDescriptor BASE_EMBEDDED {
+class ObjectMaterializationDescriptor BASE_EMBEDDED {
public:
- ArgumentsObjectMaterializationDescriptor(Address slot_address, int argc)
- : slot_address_(slot_address), arguments_length_(argc) { }
+ ObjectMaterializationDescriptor(Address slot_address, int length)
+ : slot_address_(slot_address), object_length_(length) { }
Address slot_address() const { return slot_address_; }
- int arguments_length() const { return arguments_length_; }
+ int object_length() const { return object_length_; }
private:
Address slot_address_;
- int arguments_length_;
+ int object_length_;
};
@@ -369,6 +369,10 @@
void DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index);
+ void DoTranslateObject(TranslationIterator* iterator,
+ int object_opcode,
+ int field_index);
+
enum DeoptimizerTranslatedValueType {
TRANSLATED_VALUE_IS_NATIVE,
TRANSLATED_VALUE_IS_TAGGED
@@ -394,8 +398,9 @@
Object* ComputeLiteral(int index) const;
- void AddArgumentsObject(intptr_t slot_address, int argc);
- void AddArgumentsObjectValue(intptr_t value);
+ void AddObjectStart(intptr_t slot_address, int argc);
+ void AddObjectTaggedValue(intptr_t value);
+ void AddObjectDoubleValue(double value);
void AddDoubleValue(intptr_t slot_address, double value);
static void GenerateDeoptimizationEntries(
@@ -446,8 +451,9 @@
// Array of output frame descriptions.
FrameDescription** output_;
- List<Object*> deferred_arguments_objects_values_;
- List<ArgumentsObjectMaterializationDescriptor> deferred_arguments_objects_;
+ List<Object*> deferred_objects_tagged_values_;
+ List<double> deferred_objects_double_values_;
+ List<ObjectMaterializationDescriptor> deferred_objects_;
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
#ifdef DEBUG
DisallowHeapAllocation* disallow_heap_allocation_;
@@ -698,6 +704,7 @@
SETTER_STUB_FRAME,
ARGUMENTS_ADAPTOR_FRAME,
COMPILED_STUB_FRAME,
+ ARGUMENTS_OBJECT,
REGISTER,
INT32_REGISTER,
UINT32_REGISTER,
@@ -707,7 +714,6 @@
UINT32_STACK_SLOT,
DOUBLE_STACK_SLOT,
LITERAL,
- ARGUMENTS_OBJECT,
// A prefix indicating that the next command is a duplicate of the one
// that follows it.
@@ -733,6 +739,7 @@
void BeginConstructStubFrame(int literal_id, unsigned height);
void BeginGetterStubFrame(int literal_id);
void BeginSetterStubFrame(int literal_id);
+ void BeginArgumentsObject(int args_length);
void StoreRegister(Register reg);
void StoreInt32Register(Register reg);
void StoreUint32Register(Register reg);
@@ -742,7 +749,6 @@
void StoreUint32StackSlot(int index);
void StoreDoubleStackSlot(int index);
void StoreLiteral(int literal_id);
- void StoreArgumentsObject(bool args_known, int args_index, int args_length);
void MarkDuplicate();
Zone* zone() const { return zone_; }
diff --git a/src/factory.cc b/src/factory.cc
index fbe6cb8..8b842a7 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -491,13 +491,12 @@
}
-Handle<JSGlobalPropertyCell> Factory::NewJSGlobalPropertyCell(
- Handle<Object> value) {
+Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
CALL_HEAP_FUNCTION(
isolate(),
- isolate()->heap()->AllocateJSGlobalPropertyCell(*value),
- JSGlobalPropertyCell);
+ isolate()->heap()->AllocatePropertyCell(*value),
+ PropertyCell);
}
diff --git a/src/factory.h b/src/factory.h
index 07ce96e..cde8432 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -237,8 +237,7 @@
Handle<Cell> NewCell(Handle<Object> value);
- Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
- Handle<Object> value);
+ Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
Handle<Map> NewMap(
InstanceType type,
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 49dac4a..4c5a56e 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -317,7 +317,7 @@
// 0x1700 fits in the immediate field of an ARM instruction.
DEFINE_int(interrupt_budget, 0x1700,
"execution budget before interrupt is triggered")
-DEFINE_int(type_info_threshold, 15,
+DEFINE_int(type_info_threshold, 30,
"percentage of ICs that must have type info to allow optimization")
DEFINE_int(self_opt_count, 130, "call count before self-optimization")
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 969a98d..dc5ac6a 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -123,14 +123,15 @@
static const int kMaxBackEdgeWeight = 127;
+ // Platform-specific code size multiplier.
#if V8_TARGET_ARCH_IA32
- static const int kBackEdgeDistanceUnit = 100;
+ static const int kCodeSizeMultiplier = 100;
#elif V8_TARGET_ARCH_X64
- static const int kBackEdgeDistanceUnit = 162;
+ static const int kCodeSizeMultiplier = 162;
#elif V8_TARGET_ARCH_ARM
- static const int kBackEdgeDistanceUnit = 142;
+ static const int kCodeSizeMultiplier = 142;
#elif V8_TARGET_ARCH_MIPS
- static const int kBackEdgeDistanceUnit = 142;
+ static const int kCodeSizeMultiplier = 142;
#else
#error Unsupported target architecture.
#endif
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 208b1ad..eb9d9c0 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -313,13 +313,13 @@
}
-MaybeObject* Heap::AllocateRawJSGlobalPropertyCell() {
+MaybeObject* Heap::AllocateRawPropertyCell() {
#ifdef DEBUG
isolate_->counters()->objs_since_last_full()->Increment();
isolate_->counters()->objs_since_last_young()->Increment();
#endif
MaybeObject* result =
- property_cell_space_->AllocateRaw(JSGlobalPropertyCell::kSize);
+ property_cell_space_->AllocateRaw(PropertyCell::kSize);
if (result->IsFailure()) old_gen_exhausted_ = true;
return result;
}
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 611f6a7..217d1ca 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -890,7 +890,7 @@
default: return "system / Map";
}
case CELL_TYPE: return "system / Cell";
- case PROPERTY_CELL_TYPE: return "system / JSGlobalPropertyCell";
+ case PROPERTY_CELL_TYPE: return "system / PropertyCell";
case FOREIGN_TYPE: return "system / Foreign";
case ODDBALL_TYPE: return "system / Oddball";
#define MAKE_STRUCT_CASE(NAME, Name, name) \
@@ -981,9 +981,9 @@
} else if (obj->IsCell()) {
ExtractCellReferences(entry, Cell::cast(obj));
extract_indexed_refs = false;
- } else if (obj->IsJSGlobalPropertyCell()) {
- ExtractJSGlobalPropertyCellReferences(
- entry, JSGlobalPropertyCell::cast(obj));
+ } else if (obj->IsPropertyCell()) {
+ ExtractPropertyCellReferences(
+ entry, PropertyCell::cast(obj));
extract_indexed_refs = false;
}
if (extract_indexed_refs) {
@@ -1283,8 +1283,8 @@
}
-void V8HeapExplorer::ExtractJSGlobalPropertyCellReferences(
- int entry, JSGlobalPropertyCell* cell) {
+void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
+ PropertyCell* cell) {
SetInternalReference(cell, entry, "value", cell->value());
SetInternalReference(cell, entry, "type", cell->type());
}
@@ -1386,8 +1386,8 @@
if (dictionary->IsKey(k)) {
Object* target = dictionary->ValueAt(i);
// We assume that global objects can only have slow properties.
- Object* value = target->IsJSGlobalPropertyCell()
- ? JSGlobalPropertyCell::cast(target)->value()
+ Object* value = target->IsPropertyCell()
+ ? PropertyCell::cast(target)->value()
: target;
if (k != heap_->hidden_string()) {
SetPropertyReference(js_obj, entry, String::cast(k), value);
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index 3a91f74..c9a82f0 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -465,8 +465,7 @@
void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
void ExtractCodeReferences(int entry, Code* code);
void ExtractCellReferences(int entry, Cell* cell);
- void ExtractJSGlobalPropertyCellReferences(int entry,
- JSGlobalPropertyCell* cell);
+ void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
void ExtractClosureReferences(JSObject* js_obj, int entry);
void ExtractPropertyReferences(JSObject* js_obj, int entry);
void ExtractElementReferences(JSObject* js_obj, int entry);
diff --git a/src/heap.cc b/src/heap.cc
index 5710b63..43c83e4 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -152,7 +152,6 @@
last_idle_notification_gc_count_(0),
last_idle_notification_gc_count_init_(false),
mark_sweeps_since_idle_round_started_(0),
- ms_count_at_last_idle_notification_(0),
gc_count_at_last_idle_gc_(0),
scavenges_since_last_idle_round_(kIdleScavengeThreshold),
gcs_since_last_deopt_(0),
@@ -1395,8 +1394,8 @@
for (HeapObject* heap_object = js_global_property_cell_iterator.Next();
heap_object != NULL;
heap_object = js_global_property_cell_iterator.Next()) {
- if (heap_object->IsJSGlobalPropertyCell()) {
- JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
+ if (heap_object->IsPropertyCell()) {
+ PropertyCell* cell = PropertyCell::cast(heap_object);
Address value_address = cell->ValueAddress();
scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
Address type_address = cell->TypeAddress();
@@ -2679,7 +2678,7 @@
set_cell_map(Map::cast(obj));
{ MaybeObject* maybe_obj = AllocateMap(PROPERTY_CELL_TYPE,
- JSGlobalPropertyCell::kSize);
+ PropertyCell::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_global_property_cell_map(Map::cast(obj));
@@ -2824,15 +2823,15 @@
}
-MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
+MaybeObject* Heap::AllocatePropertyCell(Object* value) {
Object* result;
- { MaybeObject* maybe_result = AllocateRawJSGlobalPropertyCell();
+ { MaybeObject* maybe_result = AllocateRawPropertyCell();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
HeapObject::cast(result)->set_map_no_write_barrier(
global_property_cell_map());
- JSGlobalPropertyCell::cast(result)->set_value(value);
- JSGlobalPropertyCell::cast(result)->set_type(Type::None());
+ PropertyCell::cast(result)->set_value(value);
+ PropertyCell::cast(result)->set_type(Type::None());
return result;
}
@@ -4725,7 +4724,7 @@
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
- // require us to change property values to JSGlobalPropertyCells.
+ // require us to change property values to PropertyCells.
ASSERT(map->NextFreePropertyIndex() == 0);
// Make sure we don't have a ton of pre-allocated slots in the
@@ -4754,7 +4753,7 @@
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
Object* value = descs->GetCallbacksObject(i);
- MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
+ MaybeObject* maybe_value = AllocatePropertyCell(value);
if (!maybe_value->ToObject(&value)) return maybe_value;
MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
@@ -5859,6 +5858,7 @@
uncommit = true;
}
CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
+ mark_sweeps_since_idle_round_started_++;
gc_count_at_last_idle_gc_ = gc_count_;
if (uncommit) {
new_space_.Shrink();
@@ -5872,6 +5872,7 @@
// Hints greater than this value indicate that
// the embedder is requesting a lot of GC work.
const int kMaxHint = 1000;
+ const int kMinHintForIncrementalMarking = 10;
// Minimal hint that allows to do full GC.
const int kMinHintForFullGC = 100;
intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
@@ -5934,18 +5935,9 @@
}
}
- int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
- mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
- ms_count_at_last_idle_notification_ = ms_count_;
-
int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
mark_sweeps_since_idle_round_started_;
- if (remaining_mark_sweeps <= 0) {
- FinishIdleRound();
- return true;
- }
-
if (incremental_marking()->IsStopped()) {
// If there are no more than two GCs left in this idle round and we are
// allowed to do a full GC, then make those GCs full in order to compact
@@ -5955,13 +5947,21 @@
if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: finalize idle round");
- } else {
+ mark_sweeps_since_idle_round_started_++;
+ } else if (hint > kMinHintForIncrementalMarking) {
incremental_marking()->Start();
}
}
- if (!incremental_marking()->IsStopped()) {
+ if (!incremental_marking()->IsStopped() &&
+ hint > kMinHintForIncrementalMarking) {
AdvanceIdleIncrementalMarking(step_size);
}
+
+ if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
+ FinishIdleRound();
+ return true;
+ }
+
return false;
}
@@ -6078,7 +6078,7 @@
map_space_->ReportStatistics();
PrintF("Cell space : ");
cell_space_->ReportStatistics();
- PrintF("JSGlobalPropertyCell space : ");
+ PrintF("PropertyCell space : ");
property_cell_space_->ReportStatistics();
PrintF("Large object space : ");
lo_space_->ReportStatistics();
diff --git a/src/heap.h b/src/heap.h
index 70d1ccb..78d9093 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -949,7 +949,7 @@
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* AllocateJSGlobalPropertyCell(Object* value);
+ MUST_USE_RESULT MaybeObject* AllocatePropertyCell(Object* value);
// Allocate Box.
MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
@@ -2131,7 +2131,7 @@
MUST_USE_RESULT inline MaybeObject* AllocateRawCell();
// Allocate an uninitialized object in the global property cell space.
- MUST_USE_RESULT inline MaybeObject* AllocateRawJSGlobalPropertyCell();
+ MUST_USE_RESULT inline MaybeObject* AllocateRawPropertyCell();
// Initializes a JSObject based on its map.
void InitializeJSObjectFromMap(JSObject* obj,
@@ -2293,7 +2293,6 @@
void StartIdleRound() {
mark_sweeps_since_idle_round_started_ = 0;
- ms_count_at_last_idle_notification_ = ms_count_;
}
void FinishIdleRound() {
@@ -2370,7 +2369,6 @@
bool last_idle_notification_gc_count_init_;
int mark_sweeps_since_idle_round_started_;
- int ms_count_at_last_idle_notification_;
unsigned int gc_count_at_last_idle_gc_;
int scavenges_since_last_idle_round_;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index b36706b..170f5ed 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -84,6 +84,10 @@
UpdateRepresentation(new_rep, h_infer, "inputs");
new_rep = RepresentationFromUses();
UpdateRepresentation(new_rep, h_infer, "uses");
+ new_rep = RepresentationFromUseRequirements();
+ if (new_rep.fits_into(Representation::Integer32())) {
+ UpdateRepresentation(new_rep, h_infer, "use requirements");
+ }
}
@@ -1147,19 +1151,14 @@
void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) {
ASSERT(CheckFlag(kFlexibleRepresentation));
- Representation r;
HValue* actual_index = index()->ActualValue();
HValue* actual_length = length()->ActualValue();
Representation index_rep = actual_index->representation();
- if (!actual_length->representation().IsSmiOrTagged()) {
- r = Representation::Integer32();
- } else if ((index_rep.IsTagged() && actual_index->type().IsSmi()) ||
- index_rep.IsSmi()) {
- // If the index is smi, allow the length to be smi, since it is usually
- // already smi from loading it out of the length field of a JSArray. This
- // allows for direct comparison without untagging.
- r = Representation::Smi();
- } else {
+ Representation length_rep = actual_length->representation();
+ if (index_rep.IsTagged()) index_rep = Representation::Smi();
+ if (length_rep.IsTagged()) length_rep = Representation::Smi();
+ Representation r = index_rep.generalize(length_rep);
+ if (r.is_more_general_than(Representation::Integer32())) {
r = Representation::Integer32();
}
UpdateRepresentation(r, h_infer, "boundscheck");
@@ -1287,7 +1286,7 @@
} else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
return Representation::Double();
} else if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
- return Representation::Integer32();
+ return Representation::Smi();
} else {
return Representation::None();
}
@@ -1511,30 +1510,52 @@
}
+static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
+ // A value with an integer representation does not need to be transformed.
+ if (dividend->representation().IsInteger32()) {
+ return dividend;
+ }
+ // A change from an integer32 can be replaced by the integer32 value.
+ if (dividend->IsChange() &&
+ HChange::cast(dividend)->from().IsInteger32()) {
+ return HChange::cast(dividend)->value();
+ }
+ return NULL;
+}
+
+
HValue* HUnaryMathOperation::Canonicalize() {
if (op() == kMathFloor) {
+ HValue* val = value();
+ if (val->IsChange()) val = HChange::cast(val)->value();
+
// If the input is integer32 then we replace the floor instruction
- // with its input. This happens before the representation changes are
- // introduced.
+ // with its input.
+ if (val->representation().IsInteger32()) return val;
- // TODO(2205): The above comment is lying. All of this happens
- // *after* representation changes are introduced. We should check
- // for value->IsChange() and react accordingly if yes.
-
- if (value()->representation().IsInteger32()) return value();
-
-#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_IA32) || \
- defined(V8_TARGET_ARCH_X64)
- if (value()->IsDiv() && (value()->UseCount() == 1)) {
- // TODO(2038): Implement this optimization for non ARM architectures.
- HDiv* hdiv = HDiv::cast(value());
+ if (val->IsDiv() && (val->UseCount() == 1)) {
+ HDiv* hdiv = HDiv::cast(val);
HValue* left = hdiv->left();
HValue* right = hdiv->right();
// Try to simplify left and right values of the division.
- HValue* new_left =
- LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(left);
+ HValue* new_left = SimplifiedDividendForMathFloorOfDiv(left);
+ if (new_left == NULL &&
+ hdiv->observed_input_representation(1).IsSmiOrInteger32()) {
+ new_left = new(block()->zone())
+ HChange(left, Representation::Integer32(), false, false);
+ HChange::cast(new_left)->InsertBefore(this);
+ }
HValue* new_right =
- LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right);
+ LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right);
+ if (new_right == NULL &&
+#ifdef V8_TARGET_ARCH_ARM
+ CpuFeatures::IsSupported(SUDIV) &&
+#endif
+ hdiv->observed_input_representation(2).IsSmiOrInteger32()) {
+ new_right = new(block()->zone())
+ HChange(right, Representation::Integer32(), false, false);
+ HChange::cast(new_right)->InsertBefore(this);
+ }
// Return if left or right are not optimizable.
if ((new_left == NULL) || (new_right == NULL)) return this;
@@ -1548,26 +1569,20 @@
!HInstruction::cast(new_right)->IsLinked()) {
HInstruction::cast(new_right)->InsertBefore(this);
}
- HMathFloorOfDiv* instr = new(block()->zone()) HMathFloorOfDiv(context(),
- new_left,
- new_right);
+ HMathFloorOfDiv* instr = new(block()->zone())
+ HMathFloorOfDiv(context(), new_left, new_right);
// Replace this HMathFloor instruction by the new HMathFloorOfDiv.
instr->InsertBefore(this);
ReplaceAllUsesWith(instr);
Kill();
// We know the division had no other uses than this HMathFloor. Delete it.
- // Also delete the arguments of the division if they are not used any
- // more.
+ // Dead code elimination will deal with |left| and |right| if
+ // appropriate.
hdiv->DeleteAndReplaceWith(NULL);
- ASSERT(left->IsChange() || left->IsConstant());
- ASSERT(right->IsChange() || right->IsConstant());
- if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL);
- if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL);
// Return NULL to remove this instruction from the graph.
return NULL;
}
-#endif // V8_TARGET_ARCH_ARM
}
return this;
}
@@ -2304,6 +2319,10 @@
if (!observed_output_representation_.IsNone()) return;
new_rep = RepresentationFromUses();
UpdateRepresentation(new_rep, h_infer, "uses");
+ new_rep = RepresentationFromUseRequirements();
+ if (new_rep.fits_into(Representation::Integer32())) {
+ UpdateRepresentation(new_rep, h_infer, "use requirements");
+ }
}
@@ -3660,34 +3679,26 @@
}
-Representation HPhi::RepresentationFromUseRequirements() {
- Representation all_uses_require = Representation::None();
- bool all_uses_require_the_same = true;
+// Returns a representation if all uses agree on the same representation.
+// Integer32 is also returned when some uses are Smi but others are Integer32.
+Representation HValue::RepresentationFromUseRequirements() {
+ Representation rep = Representation::None();
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
// We check for observed_input_representation elsewhere.
Representation use_rep =
it.value()->RequiredInputRepresentation(it.index());
- // No useful info from this use -> look at the next one.
- if (use_rep.IsNone()) {
+ if (rep.IsNone()) {
+ rep = use_rep;
continue;
}
- if (use_rep.Equals(all_uses_require)) {
+ if (use_rep.IsNone() || rep.Equals(use_rep)) continue;
+ if (rep.generalize(use_rep).IsInteger32()) {
+ rep = Representation::Integer32();
continue;
}
- // This use's representation contradicts what we've seen so far.
- if (!all_uses_require.IsNone()) {
- ASSERT(!use_rep.Equals(all_uses_require));
- all_uses_require_the_same = false;
- break;
- }
- // Otherwise, initialize observed representation.
- all_uses_require = use_rep;
+ return Representation::None();
}
- if (all_uses_require_the_same) {
- return all_uses_require;
- }
-
- return Representation::None();
+ return rep;
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index d691299..7554fd8 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1150,6 +1150,7 @@
return representation();
}
Representation RepresentationFromUses();
+ Representation RepresentationFromUseRequirements();
virtual void UpdateRepresentation(Representation new_rep,
HInferRepresentation* h_infer,
const char* reason);
@@ -2016,6 +2017,9 @@
};
+class HArgumentsObject;
+
+
class HEnterInlined: public HTemplateInstruction<0> {
public:
HEnterInlined(Handle<JSFunction> closure,
@@ -2023,7 +2027,7 @@
FunctionLiteral* function,
InliningKind inlining_kind,
Variable* arguments_var,
- ZoneList<HValue*>* arguments_values,
+ HArgumentsObject* arguments_object,
bool undefined_receiver,
Zone* zone)
: closure_(closure),
@@ -2032,7 +2036,7 @@
function_(function),
inlining_kind_(inlining_kind),
arguments_var_(arguments_var),
- arguments_values_(arguments_values),
+ arguments_object_(arguments_object),
undefined_receiver_(undefined_receiver),
return_targets_(2, zone) {
}
@@ -2055,7 +2059,7 @@
}
Variable* arguments_var() { return arguments_var_; }
- ZoneList<HValue*>* arguments_values() { return arguments_values_; }
+ HArgumentsObject* arguments_object() { return arguments_object_; }
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
@@ -2066,7 +2070,7 @@
FunctionLiteral* function_;
InliningKind inlining_kind_;
Variable* arguments_var_;
- ZoneList<HValue*>* arguments_values_;
+ HArgumentsObject* arguments_object_;
bool undefined_receiver_;
ZoneList<HBasicBlock*> return_targets_;
};
@@ -3065,7 +3069,6 @@
virtual Range* InferRange(Zone* zone);
virtual void InferRepresentation(HInferRepresentation* h_infer);
- Representation RepresentationFromUseRequirements();
virtual Representation RequiredInputRepresentation(int index) {
return representation();
}
@@ -3202,25 +3205,43 @@
class HArgumentsObject: public HTemplateInstruction<0> {
public:
- HArgumentsObject() {
+ HArgumentsObject(int count, Zone* zone) : values_(count, zone) {
set_representation(Representation::Tagged());
SetFlag(kIsArguments);
}
+ const ZoneList<HValue*>* arguments_values() const { return &values_; }
+ int arguments_count() const { return values_.length(); }
+
+ void AddArgument(HValue* argument, Zone* zone) {
+ values_.Add(NULL, zone); // Resize list.
+ SetOperandAt(values_.length() - 1, argument);
+ }
+
+ virtual int OperandCount() { return values_.length(); }
+ virtual HValue* OperandAt(int index) const { return values_[index]; }
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value) {
+ values_[index] = value;
+ }
+
private:
virtual bool IsDeletable() const { return true; }
+
+ ZoneList<HValue*> values_;
};
class HConstant: public HTemplateInstruction<0> {
public:
- HConstant(Handle<Object> handle, Representation r);
+ HConstant(Handle<Object> handle, Representation r = Representation::None());
HConstant(int32_t value,
Representation r = Representation::None(),
bool is_not_in_new_space = true,
@@ -5047,7 +5068,7 @@
class HStoreGlobalCell: public HUnaryOperation {
public:
HStoreGlobalCell(HValue* value,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
PropertyDetails details)
: HUnaryOperation(value),
cell_(cell),
@@ -5055,7 +5076,7 @@
SetGVNFlag(kChangesGlobalVars);
}
- Handle<JSGlobalPropertyCell> cell() const { return cell_; }
+ Handle<PropertyCell> cell() const { return cell_; }
bool RequiresHoleCheck() {
return !details_.IsDontDelete() || details_.IsReadOnly();
}
@@ -5071,7 +5092,7 @@
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
private:
- Handle<JSGlobalPropertyCell> cell_;
+ Handle<PropertyCell> cell_;
PropertyDetails details_;
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 0676555..66b0407 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -709,13 +709,9 @@
HInstruction* HGraphBuilder::IfBuilder::IfCompare(
HValue* left,
HValue* right,
- Token::Value token,
- Representation input_representation) {
+ Token::Value token) {
HCompareIDAndBranch* compare =
new(zone()) HCompareIDAndBranch(left, right, token);
- compare->set_observed_input_representation(input_representation,
- input_representation);
- compare->AssumeRepresentation(input_representation);
AddCompare(compare);
return compare;
}
@@ -1004,7 +1000,7 @@
HValue* context = environment()->LookupContext();
int num_parameters = graph()->info()->num_parameters();
HValue* params = AddInstruction(new(graph()->zone())
- HConstant(num_parameters, Representation::Integer32()));
+ HConstant(num_parameters));
HReturn* return_instruction = new(graph()->zone())
HReturn(value, context, params);
current_block()->FinishExit(return_instruction);
@@ -1169,7 +1165,6 @@
if (is_js_array) {
HValue* new_length = AddInstruction(
HAdd::New(zone, context, length, graph_->GetConstant1()));
- new_length->AssumeRepresentation(Representation::Integer32());
new_length->ClearFlag(HValue::kCanOverflow);
Representation representation = IsFastElementsKind(kind)
@@ -1342,20 +1337,16 @@
int elements_size = IsFastDoubleElementsKind(kind)
? kDoubleSize : kPointerSize;
- HConstant* elements_size_value =
- new(zone) HConstant(elements_size, Representation::Integer32());
+ HConstant* elements_size_value = new(zone) HConstant(elements_size);
AddInstruction(elements_size_value);
HValue* mul = AddInstruction(
HMul::New(zone, context, capacity, elements_size_value));
- mul->AssumeRepresentation(Representation::Integer32());
mul->ClearFlag(HValue::kCanOverflow);
- HConstant* header_size =
- new(zone) HConstant(FixedArray::kHeaderSize, Representation::Integer32());
+ HConstant* header_size = new(zone) HConstant(FixedArray::kHeaderSize);
AddInstruction(header_size);
HValue* total_size = AddInstruction(
HAdd::New(zone, context, mul, header_size));
- total_size->AssumeRepresentation(Representation::Integer32());
total_size->ClearFlag(HValue::kCanOverflow);
HAllocate::Flags flags = HAllocate::DefaultFlags(kind);
@@ -1413,9 +1404,7 @@
AddStore(array, HObjectAccess::ForMap(), array_map);
HConstant* empty_fixed_array =
- new(zone()) HConstant(
- Handle<FixedArray>(isolate()->heap()->empty_fixed_array()),
- Representation::Tagged());
+ new(zone()) HConstant(isolate()->factory()->empty_fixed_array());
AddInstruction(empty_fixed_array);
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
@@ -1454,20 +1443,16 @@
HValue* half_old_capacity =
AddInstruction(HShr::New(zone, context, old_capacity,
graph_->GetConstant1()));
- half_old_capacity->AssumeRepresentation(Representation::Integer32());
half_old_capacity->ClearFlag(HValue::kCanOverflow);
HValue* new_capacity = AddInstruction(
HAdd::New(zone, context, half_old_capacity, old_capacity));
- new_capacity->AssumeRepresentation(Representation::Integer32());
new_capacity->ClearFlag(HValue::kCanOverflow);
- HValue* min_growth =
- AddInstruction(new(zone) HConstant(16, Representation::Integer32()));
+ HValue* min_growth = AddInstruction(new(zone) HConstant(16));
new_capacity = AddInstruction(
HAdd::New(zone, context, new_capacity, min_growth));
- new_capacity->AssumeRepresentation(Representation::Integer32());
new_capacity->ClearFlag(HValue::kCanOverflow);
return new_capacity;
@@ -1523,10 +1508,8 @@
double nan_double = FixedDoubleArray::hole_nan_as_double();
Zone* zone = this->zone();
HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
- ? AddInstruction(new(zone) HConstant(factory->the_hole_value(),
- Representation::Tagged()))
- : AddInstruction(new(zone) HConstant(nan_double,
- Representation::Double()));
+ ? AddInstruction(new(zone) HConstant(factory->the_hole_value()))
+ : AddInstruction(new(zone) HConstant(nan_double));
// Special loop unfolding case
static const int kLoopUnfoldLimit = 4;
@@ -1639,8 +1622,7 @@
HAllocate::Flags allocate_flags = HAllocate::DefaultFlags(kind);
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
- HValue* size_in_bytes =
- AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
+ HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
HInstruction* object =
AddInstruction(new(zone) HAllocate(context,
size_in_bytes,
@@ -1763,7 +1745,7 @@
HInstruction* HGraphBuilder::BuildGetArrayFunction(HValue* context) {
HInstruction* native_context = BuildGetNativeContext(context);
HInstruction* index = AddInstruction(new(zone())
- HConstant(Context::ARRAY_FUNCTION_INDEX, Representation::Integer32()));
+ HConstant(Context::ARRAY_FUNCTION_INDEX));
return AddInstruction(new (zone())
HLoadKeyed(native_context, index, NULL, FAST_ELEMENTS));
@@ -1799,13 +1781,13 @@
HInstruction* native_context = builder()->BuildGetNativeContext(context);
HInstruction* index = builder()->AddInstruction(new(zone())
- HConstant(Context::JS_ARRAY_MAPS_INDEX, Representation::Integer32()));
+ HConstant(Context::JS_ARRAY_MAPS_INDEX));
HInstruction* map_array = builder()->AddInstruction(new(zone())
HLoadKeyed(native_context, index, NULL, FAST_ELEMENTS));
HInstruction* kind_index = builder()->AddInstruction(new(zone())
- HConstant(kind_, Representation::Integer32()));
+ HConstant(kind_));
return builder()->AddInstruction(new(zone())
HLoadKeyed(map_array, kind_index, NULL, FAST_ELEMENTS));
@@ -1838,20 +1820,16 @@
base_size += FixedArray::kHeaderSize;
}
- HInstruction* elements_size_value = new(zone())
- HConstant(elements_size(), Representation::Integer32());
+ HInstruction* elements_size_value = new(zone()) HConstant(elements_size());
AddInstruction(elements_size_value);
HInstruction* mul = HMul::New(zone(), context, length_node,
elements_size_value);
- mul->AssumeRepresentation(Representation::Integer32());
mul->ClearFlag(HValue::kCanOverflow);
AddInstruction(mul);
- HInstruction* base = new(zone()) HConstant(base_size,
- Representation::Integer32());
+ HInstruction* base = new(zone()) HConstant(base_size);
AddInstruction(base);
HInstruction* total_size = HAdd::New(zone(), context, base, mul);
- total_size->AssumeRepresentation(Representation::Integer32());
total_size->ClearFlag(HValue::kCanOverflow);
AddInstruction(total_size);
return total_size;
@@ -1868,8 +1846,7 @@
? FixedDoubleArray::SizeFor(initial_capacity())
: FixedArray::SizeFor(initial_capacity());
- HConstant* array_size =
- new(zone()) HConstant(base_size, Representation::Integer32());
+ HConstant* array_size = new(zone()) HConstant(base_size);
AddInstruction(array_size);
return array_size;
}
@@ -1877,8 +1854,7 @@
HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
HValue* size_in_bytes = EstablishEmptyArrayAllocationSize();
- HConstant* capacity =
- new(zone()) HConstant(initial_capacity(), Representation::Integer32());
+ HConstant* capacity = new(zone()) HConstant(initial_capacity());
AddInstruction(capacity);
return AllocateArray(size_in_bytes,
capacity,
@@ -1956,8 +1932,7 @@
HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
Handle<Map> map) {
- HValue* constant =
- AddInstruction(new(zone()) HConstant(map, Representation::Tagged()));
+ HValue* constant = AddInstruction(new(zone()) HConstant(map));
HStoreNamedField *instr =
new(zone()) HStoreNamedField(object, HObjectAccess::ForMap(), constant);
AddInstruction(instr);
@@ -3010,6 +2985,15 @@
}
continue;
}
+ if (current->IsReturn()) {
+ // Drop mergeable simulates in the list. This is safe because
+ // simulates after instructions with side effects are never added
+ // to the merge list.
+ while (!mergelist.is_empty()) {
+ mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
+ }
+ continue;
+ }
// Skip the non-simulates and the first simulate.
if (!current->IsSimulate()) continue;
if (first) {
@@ -3546,6 +3530,7 @@
function_return_(NULL),
test_context_(NULL),
entry_(NULL),
+ arguments_object_(NULL),
arguments_elements_(NULL),
outer_(owner->function_state()) {
if (outer_ != NULL) {
@@ -3818,6 +3803,13 @@
} while (false)
+#define CHECK_ALIVE_OR_RETURN(call, value) \
+ do { \
+ call; \
+ if (HasStackOverflow() || current_block() == NULL) return value; \
+ } while (false)
+
+
void HOptimizedGraphBuilder::Bailout(const char* reason) {
current_info()->set_bailout_reason(reason);
SetStackOverflow();
@@ -4693,22 +4685,22 @@
void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
HConstant* undefined_constant = new(zone()) HConstant(
- isolate()->factory()->undefined_value(), Representation::Tagged());
+ isolate()->factory()->undefined_value());
AddInstruction(undefined_constant);
graph()->set_undefined_constant(undefined_constant);
- HArgumentsObject* object = new(zone()) HArgumentsObject;
- AddInstruction(object);
- graph()->SetArgumentsObject(object);
-
- // Set the initial values of parameters including "this". "This" has
- // parameter index 0.
+ // Create an arguments object containing the initial parameters. Set the
+ // initial values of parameters including "this" having parameter index 0.
ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
-
+ HArgumentsObject* arguments_object =
+ new(zone()) HArgumentsObject(environment()->parameter_count(), zone());
for (int i = 0; i < environment()->parameter_count(); ++i) {
HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
+ arguments_object->AddArgument(parameter, zone());
environment()->Bind(i, parameter);
}
+ AddInstruction(arguments_object);
+ graph()->SetArgumentsObject(arguments_object);
// First special is HContext.
HInstruction* context = AddInstruction(new(zone()) HContext);
@@ -5032,7 +5024,7 @@
label_value,
Token::EQ_STRICT);
compare_->set_observed_input_representation(
- Representation::Integer32(), Representation::Integer32());
+ Representation::Smi(), Representation::Smi());
compare = compare_;
} else {
compare = new(zone()) HStringCompareAndBranch(context, tag_value,
@@ -5397,7 +5389,7 @@
HCompareIDAndBranch* compare_index =
new(zone()) HCompareIDAndBranch(index, limit, Token::LT);
compare_index->set_observed_input_representation(
- Representation::Integer32(), Representation::Integer32());
+ Representation::Smi(), Representation::Smi());
HBasicBlock* loop_body = graph()->CreateBasicBlock();
HBasicBlock* loop_successor = graph()->CreateBasicBlock();
@@ -5619,8 +5611,7 @@
Handle<Object> constant_value =
isolate()->factory()->GlobalConstantFor(variable->name());
if (!constant_value.is_null()) {
- HConstant* instr =
- new(zone()) HConstant(constant_value, Representation::Tagged());
+ HConstant* instr = new(zone()) HConstant(constant_value);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -5635,7 +5626,7 @@
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
HLoadGlobalCell* instr =
new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
return ast_context()->ReturnInstruction(instr, expr->id());
@@ -5680,8 +5671,7 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- HConstant* instr =
- new(zone()) HConstant(expr->handle(), Representation::None());
+ HConstant* instr = new(zone()) HConstant(expr->handle());
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -5906,13 +5896,13 @@
? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(closure_literals, Representation::Tagged()))));
+ new(zone()) HConstant(closure_literals))));
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(literal_index, Representation::Tagged()))));
+ new(zone()) HConstant(literal_index))));
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(constant_properties, Representation::Tagged()))));
+ new(zone()) HConstant(constant_properties))));
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(flags, Representation::Tagged()))));
+ new(zone()) HConstant(flags))));
Runtime::FunctionId function_id =
(expr->depth() > 1 || expr->may_store_doubles())
@@ -6070,22 +6060,22 @@
boilerplate_elements_kind, true)) {
IfBuilder builder(this);
HValue* boilerplate = AddInstruction(new(zone())
- HConstant(original_boilerplate_object, Representation::Tagged()));
+ HConstant(original_boilerplate_object));
HValue* elements_kind = AddInstruction(new(zone())
HElementsKind(boilerplate));
HValue* expected_kind = AddInstruction(new(zone())
- HConstant(boilerplate_elements_kind, Representation::Integer32()));
+ HConstant(boilerplate_elements_kind));
builder.IfCompare(elements_kind, expected_kind, Token::EQ);
builder.Then();
builder.ElseDeopt();
}
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(literals, Representation::Tagged()))));
+ new(zone()) HConstant(literals))));
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(literal_index, Representation::Tagged()))));
+ new(zone()) HConstant(literal_index))));
AddInstruction(new(zone()) HPushArgument(AddInstruction(
- new(zone()) HConstant(constants, Representation::Tagged()))));
+ new(zone()) HConstant(constants))));
Runtime::FunctionId function_id = (expr->depth() > 1)
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
@@ -6099,6 +6089,8 @@
// The array is expected in the bailout environment during computation
// of the property values and is the value of the entire expression.
Push(literal);
+ // The literal index is on the stack, too.
+ Push(AddInstruction(new(zone()) HConstant(expr->literal_index())));
HInstruction* elements = NULL;
@@ -6136,6 +6128,8 @@
AddSimulate(expr->GetIdForElement(i));
}
+
+ Drop(1); // array literal index
return ast_context()->ReturnValue(Pop());
}
@@ -6239,7 +6233,7 @@
// The store requires a mutable HeapNumber to be allocated.
NoObservableSideEffectsScope no_side_effects(this);
HInstruction* heap_number_size = AddInstruction(new(zone()) HConstant(
- HeapNumber::kSize, Representation::Integer32()));
+ HeapNumber::kSize));
HInstruction* double_box = AddInstruction(new(zone()) HAllocate(
environment()->LookupContext(), heap_number_size,
HType::HeapNumber(), HAllocate::CAN_ALLOCATE_IN_NEW_SPACE));
@@ -6315,50 +6309,20 @@
}
-bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad(
+HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name) {
- if (!name->Equals(isolate()->heap()->length_string())) return false;
-
- for (int i = 0; i < types->length(); i++) {
- if (types->at(i)->instance_type() != JS_ARRAY_TYPE) return false;
- }
-
- BuildCheckNonSmi(object);
-
- HInstruction* typecheck =
- AddInstruction(HCheckMaps::New(object, types, zone()));
- HInstruction* instr = new(zone())
- HLoadNamedField(object, HObjectAccess::ForArrayLength(), typecheck);
-
- instr->set_position(expr->position());
- ast_context()->ReturnInstruction(instr, expr->id());
- return true;
-}
-
-
-void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
- HValue* object,
- SmallMapList* types,
- Handle<String> name) {
-
- if (HandlePolymorphicArrayLengthLoad(expr, object, types, name))
- return;
-
- BuildCheckNonSmi(object);
-
// Use monomorphic load if property lookup results in the same field index
// for all maps. Requires special map check on the set of all handled maps.
- HInstruction* instr = NULL;
+ if (types->length() > kMaxLoadPolymorphism) return NULL;
+
LookupResult lookup(isolate());
int count;
Representation representation = Representation::None();
HObjectAccess access = HObjectAccess::ForMap(); // initial value unused.
- for (count = 0;
- count < types->length() && count < kMaxLoadPolymorphism;
- ++count) {
+ for (count = 0; count < types->length(); ++count) {
Handle<Map> map = types->at(count);
if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
@@ -6369,7 +6333,6 @@
if (count == 0) {
// First time through the loop; set access and representation.
access = new_access;
- representation = new_representation;
} else if (!representation.IsCompatibleForLoad(new_representation)) {
// Representations did not match.
break;
@@ -6380,21 +6343,94 @@
// In-objectness did not match.
break;
}
+ representation = representation.generalize(new_representation);
+ }
+
+ if (count != types->length()) return NULL;
+
+ // Everything matched; can use monomorphic load.
+ BuildCheckNonSmi(object);
+ AddInstruction(HCheckMaps::New(object, types, zone()));
+ return BuildLoadNamedField(object, access, representation);
+}
+
+
+void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
+ Property* expr,
+ HValue* object,
+ SmallMapList* types,
+ Handle<String> name) {
+ HInstruction* instr = TryLoadPolymorphicAsMonomorphic(
+ expr, object, types, name);
+ if (instr == NULL) {
+ // Something did not match; must use a polymorphic load.
+ BuildCheckNonSmi(object);
+ HValue* context = environment()->LookupContext();
+ instr = new(zone()) HLoadNamedFieldPolymorphic(
+ context, object, types, name, zone());
+ }
+
+ instr->set_position(expr->position());
+ return ast_context()->ReturnInstruction(instr, expr->id());
+}
+
+
+bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
+ Assignment* expr,
+ HValue* object,
+ HValue* value,
+ SmallMapList* types,
+ Handle<String> name) {
+ // Use monomorphic store if property lookup results in the same field index
+ // for all maps. Requires special map check on the set of all handled maps.
+ if (types->length() > kMaxStorePolymorphism) return false;
+
+ // TODO(verwaest): Merge the checking logic with the code in
+ // TryLoadPolymorphicAsMonomorphic.
+ LookupResult lookup(isolate());
+ int count;
+ Representation representation = Representation::None();
+ HObjectAccess access = HObjectAccess::ForMap(); // initial value unused.
+ for (count = 0; count < types->length(); ++count) {
+ Handle<Map> map = types->at(count);
+ // Pass false to ignore transitions.
+ if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
+
+ HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
+ Representation new_representation =
+ ComputeLoadStoreRepresentation(map, &lookup);
+
+ if (count == 0) {
+ // First time through the loop; set access and representation.
+ access = new_access;
+ representation = new_representation;
+ } else if (!representation.IsCompatibleForStore(new_representation)) {
+ // Representations did not match.
+ break;
+ } else if (access.offset() != new_access.offset()) {
+ // Offsets did not match.
+ break;
+ } else if (access.IsInobject() != new_access.IsInobject()) {
+ // In-objectness did not match.
+ break;
+ }
}
- if (count == types->length()) {
- // Everything matched; can use monomorphic load.
- AddInstruction(HCheckMaps::New(object, types, zone()));
- instr = BuildLoadNamedField(object, access, representation);
- } else {
- // Something did not match; must use a polymorphic load.
- HValue* context = environment()->LookupContext();
- instr = new(zone()) HLoadNamedFieldPolymorphic(
- context, object, types, name, zone());
- }
+ if (count != types->length()) return false;
- instr->set_position(expr->position());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ // Everything matched; can use monomorphic store.
+ BuildCheckNonSmi(object);
+ AddInstruction(HCheckMaps::New(object, types, zone()));
+ HInstruction* store;
+ CHECK_ALIVE_OR_RETURN(
+ store = BuildStoreNamedField(object, name, value, types->at(0), &lookup),
+ true);
+ Push(value);
+ store->set_position(expr->position());
+ AddInstruction(store);
+ AddSimulate(expr->AssignmentId());
+ ast_context()->ReturnValue(Pop());
+ return true;
}
@@ -6404,6 +6440,10 @@
HValue* value,
SmallMapList* types,
Handle<String> name) {
+ if (TryStorePolymorphicAsMonomorphic(expr, object, value, types, name)) {
+ return;
+ }
+
// TODO(ager): We should recognize when the prototype chains for different
// maps are identical. In that case we can avoid repeatedly generating the
// same prototype map checks.
@@ -6426,8 +6466,8 @@
set_current_block(if_true);
HInstruction* instr;
- CHECK_ALIVE(instr =
- BuildStoreNamedField(object, name, value, map, &lookup));
+ CHECK_ALIVE(
+ instr = BuildStoreNamedField(object, name, value, map, &lookup));
instr->set_position(expr->position());
// Goto will add the HSimulate for the store.
AddInstruction(instr);
@@ -6471,7 +6511,7 @@
ASSERT(join != NULL);
join->SetJoinId(expr->id());
set_current_block(join);
- if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
+ if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
}
@@ -6566,7 +6606,7 @@
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
HInstruction* instr =
new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails());
instr->set_position(position);
@@ -6682,10 +6722,11 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
- HInstruction* load;
+ HInstruction* load = NULL;
+ SmallMapList* types = prop->GetReceiverTypes();
bool monomorphic = prop->IsMonomorphic();
if (monomorphic) {
- map = prop->GetReceiverTypes()->first();
+ map = types->first();
// We can't generate code for a monomorphic dict mode load so
// just pretend it is not monomorphic.
if (map->is_dictionary_map()) monomorphic = false;
@@ -6698,9 +6739,10 @@
} else {
load = BuildLoadNamedMonomorphic(object, name, prop, map);
}
- } else {
- load = BuildLoadNamedGeneric(object, name, prop);
+ } else if (types != NULL && types->length() > 1) {
+ load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name);
}
+ if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop);
PushAndAdd(load);
if (load->HasObservableSideEffects()) {
AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
@@ -6966,6 +7008,8 @@
Property* expr) {
if (expr->IsUninitialized()) {
AddSoftDeoptimize();
+ } else {
+ // OS::DebugBreak();
}
HValue* context = environment()->LookupContext();
return new(zone()) HLoadNamedGeneric(context, object, name);
@@ -7013,7 +7057,7 @@
if (lookup.IsConstantFunction()) {
AddCheckMap(object, map);
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
- return new(zone()) HConstant(function, Representation::Tagged());
+ return new(zone()) HConstant(function);
}
// Handle a load from a known field somewhere in the prototype chain.
@@ -7025,8 +7069,7 @@
AddCheckMap(object, map);
AddInstruction(new(zone()) HCheckPrototypeMaps(
prototype, holder, zone(), top_info()));
- HValue* holder_value = AddInstruction(new(zone())
- HConstant(holder, Representation::Tagged()));
+ HValue* holder_value = AddInstruction(new(zone()) HConstant(holder));
return BuildLoadNamedField(holder_value,
HObjectAccess::ForField(holder_map, &lookup, name),
ComputeLoadStoreRepresentation(map, &lookup));
@@ -7041,7 +7084,7 @@
AddInstruction(new(zone()) HCheckPrototypeMaps(
prototype, holder, zone(), top_info()));
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map));
- return new(zone()) HConstant(function, Representation::Tagged());
+ return new(zone()) HConstant(function);
}
// No luck, do a generic load.
@@ -7428,7 +7471,8 @@
HEnterInlined* entry = function_state()->entry();
entry->set_arguments_pushed();
- ZoneList<HValue*>* arguments_values = entry->arguments_values();
+ HArgumentsObject* arguments = entry->arguments_object();
+ const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
HInstruction* insert_after = entry;
for (int i = 0; i < arguments_values->length(); i++) {
@@ -8021,25 +8065,27 @@
// TODO(kmillikin): implement the same inlining on other platforms so we
// can remove the unsightly ifdefs in this function.
HConstant* context =
- new(zone()) HConstant(Handle<Context>(target->context()),
- Representation::Tagged());
+ new(zone()) HConstant(Handle<Context>(target->context()));
AddInstruction(context);
inner_env->BindContext(context);
#endif
AddSimulate(return_id);
current_block()->UpdateEnvironment(inner_env);
- ZoneList<HValue*>* arguments_values = NULL;
+ HArgumentsObject* arguments_object = NULL;
- // If the function uses arguments copy current arguments values
- // to use them for materialization.
+ // If the function uses arguments object create and bind one, also copy
+ // current arguments values to use them for materialization.
if (function->scope()->arguments() != NULL) {
+ ASSERT(function->scope()->arguments()->IsStackAllocated());
HEnvironment* arguments_env = inner_env->arguments_environment();
int arguments_count = arguments_env->parameter_count();
- arguments_values = new(zone()) ZoneList<HValue*>(arguments_count, zone());
+ arguments_object = new(zone()) HArgumentsObject(arguments_count, zone());
+ inner_env->Bind(function->scope()->arguments(), arguments_object);
for (int i = 0; i < arguments_count; i++) {
- arguments_values->Add(arguments_env->Lookup(i), zone());
+ arguments_object->AddArgument(arguments_env->Lookup(i), zone());
}
+ AddInstruction(arguments_object);
}
HEnterInlined* enter_inlined =
@@ -8048,20 +8094,12 @@
function,
function_state()->inlining_kind(),
function->scope()->arguments(),
- arguments_values,
+ arguments_object,
undefined_receiver,
zone());
function_state()->set_entry(enter_inlined);
AddInstruction(enter_inlined);
- // If the function uses arguments object create and bind one.
- if (function->scope()->arguments() != NULL) {
- ASSERT(function->scope()->arguments()->IsStackAllocated());
- inner_env->Bind(function->scope()->arguments(),
- graph()->GetArgumentsObject());
- }
-
-
VisitDeclarations(target_info.scope()->declarations());
VisitStatements(function->body());
if (HasStackOverflow()) {
@@ -8367,16 +8405,14 @@
result =
HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
} else if (exponent == -0.5) {
- HConstant* double_one = new(zone()) HConstant(
- 1, Representation::Double());
- AddInstruction(double_one);
+ HValue* one = graph()->GetConstant1();
HInstruction* sqrt =
HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
AddInstruction(sqrt);
// MathPowHalf doesn't have side effects so there's no need for
// an environment simulation here.
ASSERT(!sqrt->HasObservableSideEffects());
- result = HDiv::New(zone(), context, double_one, sqrt);
+ result = HDiv::New(zone(), context, one, sqrt);
} else if (exponent == 2.0) {
result = HMul::New(zone(), context, left, left);
}
@@ -8493,13 +8529,10 @@
} else {
// We are inside inlined function and we know exactly what is inside
// arguments object. But we need to be able to materialize at deopt.
- // TODO(mstarzinger): For now we just ensure arguments are pushed
- // right after HEnterInlined, but we could be smarter about this.
- EnsureArgumentsArePushedForAccess();
ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
- function_state()->entry()->arguments_values()->length());
- HEnterInlined* entry = function_state()->entry();
- ZoneList<HValue*>* arguments_values = entry->arguments_values();
+ function_state()->entry()->arguments_object()->arguments_count());
+ HArgumentsObject* args = function_state()->entry()->arguments_object();
+ const ZoneList<HValue*>* arguments_values = args->arguments_values();
int arguments_count = arguments_values->length();
PushAndAdd(new(zone()) HWrapReceiver(receiver, function));
for (int i = 1; i < arguments_count; i++) {
@@ -8845,8 +8878,7 @@
// Allocate an instance of the implicit receiver object.
HValue* size_in_bytes =
- AddInstruction(new(zone()) HConstant(instance_size,
- Representation::Integer32()));
+ AddInstruction(new(zone()) HConstant(instance_size));
HAllocate::Flags flags = HAllocate::DefaultFlags();
if (FLAG_pretenuring_call_new &&
@@ -8864,8 +8896,7 @@
// Load the initial map from the constructor.
HValue* constructor_value =
- AddInstruction(new(zone()) HConstant(constructor,
- Representation::Tagged()));
+ AddInstruction(new(zone()) HConstant(constructor));
HValue* initial_map_value =
AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset(
JSFunction::kPrototypeOrInitialMapOffset));
@@ -8877,8 +8908,7 @@
HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset),
initial_map_value);
HValue* empty_fixed_array =
- AddInstruction(new(zone()) HConstant(factory->empty_fixed_array(),
- Representation::Tagged()));
+ AddInstruction(new(zone()) HConstant(factory->empty_fixed_array()));
AddStore(receiver,
HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset),
empty_fixed_array);
@@ -9076,11 +9106,11 @@
HValue* context = environment()->LookupContext();
HInstruction* instr =
HMul::New(zone(), context, value, graph()->GetConstantMinus1());
- TypeInfo info = expr->type();
- Representation rep = ToRepresentation(info);
- if (info.IsUninitialized()) {
+ Handle<Type> type = expr->type();
+ Representation rep = ToRepresentation(type);
+ if (type->Is(Type::None())) {
AddSoftDeoptimize();
- info = TypeInfo::Unknown();
+ type = handle(Type::Any(), isolate());
}
if (instr->IsBinaryOperation()) {
HBinaryOperation::cast(instr)->set_observed_input_representation(1, rep);
@@ -9093,8 +9123,8 @@
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* value = Pop();
- TypeInfo info = expr->type();
- if (info.IsUninitialized()) {
+ Handle<Type> info = expr->type();
+ if (info->Is(Type::None())) {
AddSoftDeoptimize();
}
HInstruction* instr = new(zone()) HBitNot(value);
@@ -9274,10 +9304,11 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
- HInstruction* load;
+ HInstruction* load = NULL;
bool monomorphic = prop->IsMonomorphic();
+ SmallMapList* types = prop->GetReceiverTypes();
if (monomorphic) {
- map = prop->GetReceiverTypes()->first();
+ map = types->first();
if (map->is_dictionary_map()) monomorphic = false;
}
if (monomorphic) {
@@ -9288,9 +9319,10 @@
} else {
load = BuildLoadNamedMonomorphic(object, name, prop, map);
}
- } else {
- load = BuildLoadNamedGeneric(object, name, prop);
+ } else if (types != NULL && types->length() > 1) {
+ load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name);
}
+ if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop);
PushAndAdd(load);
if (load->HasObservableSideEffects()) {
AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
@@ -9378,7 +9410,7 @@
int32_t i = c_index->NumberValueAsInteger32();
Handle<String> s = c_string->StringValue();
if (i < 0 || i >= s->length()) {
- return new(zone()) HConstant(OS::nan_value(), Representation::Double());
+ return new(zone()) HConstant(OS::nan_value());
}
return new(zone()) HConstant(s->Get(i));
}
@@ -9454,24 +9486,26 @@
HValue* left,
HValue* right) {
HValue* context = environment()->LookupContext();
- TypeInfo left_info = expr->left_type();
- TypeInfo right_info = expr->right_type();
- TypeInfo result_info = expr->result_type();
+ Handle<Type> left_type = expr->left_type();
+ Handle<Type> right_type = expr->right_type();
+ Handle<Type> result_type = expr->result_type();
bool has_fixed_right_arg = expr->has_fixed_right_arg();
int fixed_right_arg_value = expr->fixed_right_arg_value();
- Representation left_rep = ToRepresentation(left_info);
- Representation right_rep = ToRepresentation(right_info);
- Representation result_rep = ToRepresentation(result_info);
- if (left_info.IsUninitialized()) {
- // Can't have initialized one but not the other.
- ASSERT(right_info.IsUninitialized());
+ Representation left_rep = ToRepresentation(left_type);
+ Representation right_rep = ToRepresentation(right_type);
+ Representation result_rep = ToRepresentation(result_type);
+ if (left_type->Is(Type::None())) {
AddSoftDeoptimize();
- left_info = right_info = TypeInfo::Unknown();
+ left_type = handle(Type::Any(), isolate());
+ }
+ if (right_type->Is(Type::None())) {
+ AddSoftDeoptimize();
+ right_type = handle(Type::Any(), isolate());
}
HInstruction* instr = NULL;
switch (expr->op()) {
case Token::ADD:
- if (left_info.IsString() && right_info.IsString()) {
+ if (left_type->Is(Type::String()) && right_type->Is(Type::String())) {
BuildCheckNonSmi(left);
AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
BuildCheckNonSmi(right);
@@ -9504,7 +9538,8 @@
break;
case Token::BIT_OR: {
HValue* operand, *shift_amount;
- if (left_info.IsInteger32() && right_info.IsInteger32() &&
+ if (left_type->Is(Type::Integer32()) &&
+ right_type->Is(Type::Integer32()) &&
MatchRotateRight(left, right, &operand, &shift_amount)) {
instr = new(zone()) HRor(context, operand, shift_amount);
} else {
@@ -9693,6 +9728,7 @@
// TODO(rossberg): this should die eventually.
Representation HOptimizedGraphBuilder::ToRepresentation(TypeInfo info) {
if (info.IsUninitialized()) return Representation::None();
+ // TODO(verwaest): Return Smi rather than Integer32.
if (info.IsSmi()) return Representation::Integer32();
if (info.IsInteger32()) return Representation::Integer32();
if (info.IsDouble()) return Representation::Double();
@@ -9926,6 +9962,10 @@
result->set_position(expr->position());
return ast_context()->ReturnInstruction(result, expr->id());
} else {
+ // TODO(verwaest): Remove once ToRepresentation properly returns Smi when
+ // the IC measures Smi.
+ if (left_type->Is(Type::Integer31())) left_rep = Representation::Smi();
+ if (right_type->Is(Type::Integer31())) right_rep = Representation::Smi();
HCompareIDAndBranch* result =
new(zone()) HCompareIDAndBranch(left, right, op);
result->set_observed_input_representation(left_rep, right_rep);
@@ -9966,8 +10006,7 @@
// this-function is not a constant, except inside an inlined body.
if (function_state()->outer() != NULL) {
return new(zone()) HConstant(
- function_state()->compilation_info()->closure(),
- Representation::Tagged());
+ function_state()->compilation_info()->closure());
} else {
return new(zone()) HThisFunction;
}
@@ -9994,9 +10033,7 @@
flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
}
- HValue* size_in_bytes =
- AddInstruction(new(zone) HConstant(total_size,
- Representation::Integer32()));
+ HValue* size_in_bytes = AddInstruction(new(zone) HConstant(total_size));
HInstruction* result =
AddInstruction(new(zone) HAllocate(context,
size_in_bytes,
@@ -10053,7 +10090,7 @@
elements_offset += AllocationSiteInfo::kSize;
*offset += AllocationSiteInfo::kSize;
HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
- original_boilerplate_object, Representation::Tagged()));
+ original_boilerplate_object));
BuildCreateAllocationSiteInfo(target, JSArray::kSize, original_boilerplate);
}
}
@@ -10078,8 +10115,7 @@
if (elements_size == 0) {
Handle<Object> elements_field =
Handle<Object>(boilerplate_object->elements(), isolate());
- elements = AddInstruction(new(zone) HConstant(
- elements_field, Representation::Tagged()));
+ elements = AddInstruction(new(zone) HConstant(elements_field));
} else {
elements = AddInstruction(new(zone) HInnerAllocatedObject(
target, elements_offset));
@@ -10091,7 +10127,7 @@
Handle<Object>(boilerplate_object->properties(), isolate());
ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
HInstruction* properties = AddInstruction(new(zone) HConstant(
- properties_field, Representation::None()));
+ properties_field));
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
AddStore(object_header, access, properties);
@@ -10100,8 +10136,7 @@
Handle<JSArray>::cast(boilerplate_object);
Handle<Object> length_field =
Handle<Object>(boilerplate_array->length(), isolate());
- HInstruction* length = AddInstruction(new(zone) HConstant(
- length_field, Representation::None()));
+ HInstruction* length = AddInstruction(new(zone) HConstant(length_field));
ASSERT(boilerplate_array->length()->IsSmi());
Representation representation =
@@ -10157,8 +10192,8 @@
offset, DONT_TRACK_ALLOCATION_SITE);
} else {
Representation representation = details.representation();
- HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
- value, Representation::Tagged()));
+ HInstruction* value_instruction =
+ AddInstruction(new(zone) HConstant(value));
if (representation.IsDouble()) {
// Allocate a HeapNumber box and store the value into it.
@@ -10178,8 +10213,7 @@
int inobject_properties = boilerplate_object->map()->inobject_properties();
HInstruction* value_instruction = AddInstruction(new(zone)
- HConstant(isolate()->factory()->one_pointer_filler_map(),
- Representation::Tagged()));
+ HConstant(isolate()->factory()->one_pointer_filler_map()));
for (int i = copied_fields; i < inobject_properties; i++) {
ASSERT(boilerplate_object->IsJSObject());
int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
@@ -10221,8 +10255,8 @@
ElementsKind kind,
HValue* object_elements) {
Zone* zone = this->zone();
- HInstruction* boilerplate_elements = AddInstruction(new(zone) HConstant(
- elements, Representation::Tagged()));
+ HInstruction* boilerplate_elements =
+ AddInstruction(new(zone) HConstant(elements));
int elements_length = elements->length();
for (int i = 0; i < elements_length; i++) {
HValue* key_constant = AddInstruction(new(zone) HConstant(i));
@@ -10244,8 +10278,8 @@
HInstruction* target,
int* offset) {
Zone* zone = this->zone();
- HInstruction* boilerplate_elements = AddInstruction(new(zone) HConstant(
- elements, Representation::Tagged()));
+ HInstruction* boilerplate_elements =
+ AddInstruction(new(zone) HConstant(elements));
int elements_length = elements->length();
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
Handle<FixedArray> original_fast_elements =
@@ -11014,6 +11048,7 @@
values_(arguments, zone),
frame_type_(frame_type),
parameter_count_(arguments),
+ specials_count_(0),
local_count_(0),
outer_(outer),
entry_(NULL),
diff --git a/src/hydrogen.h b/src/hydrogen.h
index a6f0521..73b905a 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -260,6 +260,7 @@
HStackCheck* stack_check_;
};
+
class BoundsCheckTable;
class HGraph: public ZoneObject {
public:
@@ -411,6 +412,10 @@
depends_on_empty_array_proto_elements_ = true;
}
+ bool depends_on_empty_array_proto_elements() {
+ return depends_on_empty_array_proto_elements_;
+ }
+
void RecordUint32Instruction(HInstruction* instr) {
if (uint32_instructions_ == NULL) {
uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
@@ -876,6 +881,11 @@
HEnterInlined* entry() { return entry_; }
void set_entry(HEnterInlined* entry) { entry_ = entry; }
+ HArgumentsObject* arguments_object() { return arguments_object_; }
+ void set_arguments_object(HArgumentsObject* arguments_object) {
+ arguments_object_ = arguments_object;
+ }
+
HArgumentsElements* arguments_elements() { return arguments_elements_; }
void set_arguments_elements(HArgumentsElements* arguments_elements) {
arguments_elements_ = arguments_elements;
@@ -909,6 +919,7 @@
// entry.
HEnterInlined* entry_;
+ HArgumentsObject* arguments_object_;
HArgumentsElements* arguments_elements_;
FunctionState* outer_;
@@ -1080,8 +1091,7 @@
HInstruction* IfCompare(
HValue* left,
HValue* right,
- Token::Value token,
- Representation input_representation = Representation::Integer32());
+ Token::Value token);
HInstruction* IfCompareMap(HValue* left, Handle<Map> map);
@@ -1113,10 +1123,9 @@
HInstruction* OrIfCompare(
HValue* p1,
HValue* p2,
- Token::Value token,
- Representation input_representation = Representation::Integer32()) {
+ Token::Value token) {
Or();
- return IfCompare(p1, p2, token, input_representation);
+ return IfCompare(p1, p2, token);
}
HInstruction* OrIfCompareMap(HValue* left, Handle<Map> map) {
@@ -1139,10 +1148,9 @@
HInstruction* AndIfCompare(
HValue* p1,
HValue* p2,
- Token::Value token,
- Representation input_representation = Representation::Integer32()) {
+ Token::Value token) {
And();
- return IfCompare(p1, p2, token, input_representation);
+ return IfCompare(p1, p2, token);
}
HInstruction* AndIfCompareMap(HValue* left, Handle<Map> map) {
@@ -1690,11 +1698,16 @@
HValue* object,
SmallMapList* types,
Handle<String> name);
- bool HandlePolymorphicArrayLengthLoad(Property* expr,
+ HInstruction* TryLoadPolymorphicAsMonomorphic(Property* expr,
+ HValue* object,
+ SmallMapList* types,
+ Handle<String> name);
+ void HandlePolymorphicStoreNamedField(Assignment* expr,
HValue* object,
+ HValue* value,
SmallMapList* types,
Handle<String> name);
- void HandlePolymorphicStoreNamedField(Assignment* expr,
+ bool TryStorePolymorphicAsMonomorphic(Assignment* expr,
HValue* object,
HValue* value,
SmallMapList* types,
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index aa4b8a2..f3483eb 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -4688,7 +4688,7 @@
Label initialize, done;
// Load the cache state into ecx.
- __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
+ __ mov(ecx, FieldOperand(ebx, PropertyCell::kValueOffset));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
@@ -7661,11 +7661,11 @@
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : element value to store
- // -- ebx : array literal
- // -- edi : map of array literal
// -- ecx : element index as smi
- // -- edx : array literal index in function
// -- esp[0] : return address
+ // -- esp[4] : array literal index in function
+ // -- esp[8] : array literal
+ // clobbers ebx, edx, edi
// -----------------------------------
Label element_done;
@@ -7675,6 +7675,11 @@
Label slow_elements_from_double;
Label fast_elements;
+ // Get array literal index, array literal and its map.
+ __ mov(edx, Operand(esp, 1 * kPointerSize));
+ __ mov(ebx, Operand(esp, 2 * kPointerSize));
+ __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
+
__ CheckFastElements(edi, &double_elements);
// Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index c4c1e87..54e9eaf 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -342,7 +342,7 @@
ASSERT(back_edge_target->is_bound());
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
__ j(positive, &ok, Label::kNear);
@@ -384,7 +384,7 @@
} else if (FLAG_weighted_back_edges) {
int distance = masm_->pc_offset();
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
Label ok;
@@ -1788,7 +1788,8 @@
}
if (!result_saved) {
- __ push(eax);
+ __ push(eax); // array literal.
+ __ push(Immediate(Smi::FromInt(expr->literal_index())));
result_saved = true;
}
VisitForAccumulatorValue(subexpr);
@@ -1797,7 +1798,7 @@
// Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
// cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
+ __ mov(ebx, Operand(esp, kPointerSize)); // Copy of array literal.
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
// Store the subexpression value in the array's elements.
__ mov(FieldOperand(ebx, offset), result_register());
@@ -1808,10 +1809,7 @@
INLINE_SMI_CHECK);
} else {
// Store the subexpression value in the array's elements.
- __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
- __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
__ mov(ecx, Immediate(Smi::FromInt(i)));
- __ mov(edx, Immediate(Smi::FromInt(expr->literal_index())));
StoreArrayLiteralElementStub stub;
__ CallStub(&stub);
}
@@ -1820,6 +1818,7 @@
}
if (result_saved) {
+ __ add(esp, Immediate(kPointerSize)); // literal index
context()->PlugTOS();
} else {
context()->Plug(eax);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 95c7c02..2e27097 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1482,8 +1482,8 @@
}
-void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
- StrictModeFlag strict_mode) {
+void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 5df6d81..ec87a9c 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -614,27 +614,15 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* pushed_arguments_index,
- int* pushed_arguments_count) {
+ Translation* translation) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
- int translation_size = environment->values()->length();
+ int translation_size = environment->translation_size();
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- // Function parameters are arguments to the outermost environment. The
- // arguments index points to the first element of a sequence of tagged
- // values on the stack that represent the arguments. This needs to be
- // kept in sync with the LArgumentsElements implementation.
- *pushed_arguments_index = -environment->parameter_count();
- *pushed_arguments_count = environment->parameter_count();
-
- WriteTranslation(environment->outer(),
- translation,
- pushed_arguments_index,
- pushed_arguments_count);
+ WriteTranslation(environment->outer(), translation);
bool has_closure_id = !info()->closure().is_null() &&
!info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
@@ -667,23 +655,6 @@
UNREACHABLE();
}
- // Inlined frames which push their arguments cause the index to be
- // bumped and another stack area to be used for materialization,
- // otherwise actual argument values are unknown for inlined frames.
- bool arguments_known = true;
- int arguments_index = *pushed_arguments_index;
- int arguments_count = *pushed_arguments_count;
- if (environment->entry() != NULL) {
- arguments_known = environment->entry()->arguments_pushed();
- arguments_index = arguments_index < 0
- ? GetStackSlotCount() : arguments_index + arguments_count;
- arguments_count = environment->entry()->arguments_count() + 1;
- if (environment->entry()->arguments_pushed()) {
- *pushed_arguments_index = arguments_index;
- *pushed_arguments_count = arguments_count;
- }
- }
-
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -695,10 +666,7 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
@@ -707,20 +675,36 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false,
- arguments_known,
- arguments_index,
- arguments_count);
+ false);
}
}
+ // TODO(mstarzinger): Introduce marker operands to indicate that this value
+ // is not present and must be reconstructed from the deoptimizer. Currently
+ // this is only used for the arguments object.
+ if (value == NULL) {
+ int arguments_count = environment->values()->length() - translation_size;
+ translation->BeginArgumentsObject(arguments_count);
+ for (int i = 0; i < arguments_count; ++i) {
+ LOperand* value = environment->values()->at(translation_size + i);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsRegister() ||
+ environment->spilled_registers()[value->index()] == NULL);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsDoubleRegister() ||
+ environment->spilled_double_registers()[value->index()] == NULL);
+ AddToTranslation(translation,
+ value,
+ environment->HasTaggedValueAt(translation_size + i),
+ environment->HasUint32ValueAt(translation_size + i));
+ }
+ continue;
+ }
+
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
}
}
@@ -728,17 +712,8 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count) {
- if (op == NULL) {
- // TODO(twuerthinger): Introduce marker operands to indicate that this value
- // is not present and must be reconstructed from the deoptimizer. Currently
- // this is only used for the arguments object.
- translation->StoreArgumentsObject(
- arguments_known, arguments_index, arguments_count);
- } else if (op->IsStackSlot()) {
+ bool is_uint32) {
+ if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else if (is_uint32) {
@@ -864,8 +839,6 @@
int frame_count = 0;
int jsframe_count = 0;
- int args_index = 0;
- int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@@ -873,7 +846,7 @@
}
}
Translation translation(&translations_, frame_count, jsframe_count, zone());
- WriteTranslation(environment, &translation, &args_index, &args_count);
+ WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
@@ -2912,7 +2885,7 @@
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
Register value = ToRegister(instr->value());
- Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
+ Handle<PropertyCell> cell_handle = instr->hydrogen()->cell();
// If the cell we are storing to contains the hole it could have
// been deleted from the property dictionary. In that case, we need
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 33f0eda..21f6076 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -168,10 +168,7 @@
void DoGap(LGap* instr);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* arguments_index,
- int* arguments_count);
+ void WriteTranslation(LEnvironment* environment, Translation* translation);
void EnsureRelocSpaceForDeoptimization();
@@ -285,10 +282,7 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count);
+ bool is_uint32);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 325ed2c..885b2e3 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -990,7 +990,7 @@
BailoutId ast_id = hydrogen_env->ast_id();
ASSERT(!ast_id.IsNone() ||
hydrogen_env->frame_type() != JS_FUNCTION);
- int value_count = hydrogen_env->length();
+ int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
LEnvironment* result =
new(zone()) LEnvironment(hydrogen_env->closure(),
hydrogen_env->frame_type(),
@@ -1001,13 +1001,15 @@
outer,
hydrogen_env->entry(),
zone());
+ bool needs_arguments_object_materialization = false;
int argument_index = *argument_index_accumulator;
- for (int i = 0; i < value_count; ++i) {
+ for (int i = 0; i < hydrogen_env->length(); ++i) {
if (hydrogen_env->is_special_index(i)) continue;
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
+ needs_arguments_object_materialization = true;
op = NULL;
} else if (value->IsPushArgument()) {
op = new(zone()) LArgument(argument_index++);
@@ -1019,6 +1021,21 @@
value->CheckFlag(HInstruction::kUint32));
}
+ if (needs_arguments_object_materialization) {
+ HArgumentsObject* arguments = hydrogen_env->entry() == NULL
+ ? graph()->GetArgumentsObject()
+ : hydrogen_env->entry()->arguments_object();
+ ASSERT(arguments->IsLinked());
+ for (int i = 1; i < arguments->arguments_count(); ++i) {
+ HValue* value = arguments->arguments_values()->at(i);
+ ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
+ LOperand* op = UseAny(value);
+ result->AddValue(op,
+ value->representation(),
+ value->CheckFlag(HInstruction::kUint32));
+ }
+ }
+
if (hydrogen_env->frame_type() == JS_FUNCTION) {
*argument_index_accumulator = argument_index;
}
@@ -1453,19 +1470,6 @@
}
-HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
- // A value with an integer representation does not need to be transformed.
- if (dividend->representation().IsInteger32()) {
- return dividend;
- // A change from an integer32 can be replaced by the integer32 value.
- } else if (dividend->IsChange() &&
- HChange::cast(dividend)->from().IsInteger32()) {
- return HChange::cast(dividend)->value();
- }
- return NULL;
-}
-
-
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
if (divisor->IsConstant() &&
HConstant::cast(divisor)->HasInteger32Value()) {
@@ -2730,8 +2734,9 @@
undefined,
instr->inlining_kind(),
instr->undefined_receiver());
- if (instr->arguments_var() != NULL) {
- inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
+ // Only replay binding of arguments object if it wasn't removed from graph.
+ if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
+ inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index e43672c..ed33668 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -2813,7 +2813,6 @@
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
- static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
LInstruction* DoMathFloor(HUnaryMathOperation* instr);
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 60c5c26..17d4aac 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1973,6 +1973,8 @@
void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
+ Address thunk_address,
+ Operand thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset) {
@@ -1998,8 +2000,26 @@
PopSafepointRegisters();
}
+
+ Label profiler_disabled;
+ Label end_profiler_check;
+ bool* is_profiling_flag =
+ isolate()->cpu_profiler()->is_profiling_address();
+ STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+ mov(eax, Immediate(reinterpret_cast<Address>(is_profiling_flag)));
+ cmpb(Operand(eax, 0), 0);
+ j(zero, &profiler_disabled);
+
+ // Additional parameter is the address of the actual getter function.
+ mov(thunk_last_arg, Immediate(function_address));
+ // Call the api function.
+ call(thunk_address, RelocInfo::RUNTIME_ENTRY);
+ jmp(&end_profiler_check);
+
+ bind(&profiler_disabled);
// Call the api function.
call(function_address, RelocInfo::RUNTIME_ENTRY);
+ bind(&end_profiler_check);
if (FLAG_log_timer_events) {
FrameScope frame(this, StackFrame::MANUAL);
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 8380507..7d780f0 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -784,6 +784,8 @@
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address,
+ Address thunk_address,
+ Operand thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_ebp);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 93923a7..c0ee28a 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -503,7 +503,12 @@
STATIC_ASSERT(kFastApiCallArguments == 6);
__ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
- const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
+
+ // API function gets reference to the v8::Arguments. If CPU profiler
+ // is enabled wrapper function will be called and we need to pass
+ // address of the callback as additional parameter, always allocate
+ // space for it.
+ const int kApiArgc = 1 + 1;
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
@@ -517,20 +522,26 @@
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
// v8::Arguments::implicit_args_.
- __ mov(ApiParameterOperand(1, returns_handle), eax);
+ __ mov(ApiParameterOperand(2, returns_handle), eax);
__ add(eax, Immediate(argc * kPointerSize));
// v8::Arguments::values_.
- __ mov(ApiParameterOperand(2, returns_handle), eax);
+ __ mov(ApiParameterOperand(3, returns_handle), eax);
// v8::Arguments::length_.
- __ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
+ __ Set(ApiParameterOperand(4, returns_handle), Immediate(argc));
// v8::Arguments::is_construct_call_.
- __ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
+ __ Set(ApiParameterOperand(5, returns_handle), Immediate(0));
// v8::InvocationCallback's argument.
- __ lea(eax, ApiParameterOperand(1, returns_handle));
+ __ lea(eax, ApiParameterOperand(2, returns_handle));
__ mov(ApiParameterOperand(0, returns_handle), eax);
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeInvocationCallback)
+ : FUNCTION_ADDR(&InvokeFunctionCallback);
+
__ CallApiFunctionAndReturn(function_address,
+ thunk_address,
+ ApiParameterOperand(1, returns_handle),
argc + kFastApiCallArguments + 1,
returns_handle,
kFastApiCallArguments + 1);
@@ -753,13 +764,13 @@
Handle<Name> name,
Register scratch,
Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
+ Handle<PropertyCell> cell =
GlobalObject::EnsurePropertyCell(global, name);
ASSERT(cell->value()->IsTheHole());
Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
if (Serializer::enabled()) {
__ mov(scratch, Immediate(cell));
- __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
Immediate(the_hole));
} else {
__ cmp(Operand::ForCell(cell), Immediate(the_hole));
@@ -839,8 +850,14 @@
Register storage_reg = name_reg;
- if (FLAG_track_fields && representation.IsSmi()) {
- __ JumpIfNotSmi(value_reg, miss_restore_name);
+ if (details.type() == CONSTANT_FUNCTION) {
+ Handle<HeapObject> constant(
+ HeapObject::cast(descriptors->GetValue(descriptor)));
+ __ LoadHeapObject(scratch1, constant);
+ __ cmp(value_reg, scratch1);
+ __ j(not_equal, miss_restore_name);
+ } else if (FLAG_track_fields && representation.IsSmi()) {
+ __ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
@@ -884,7 +901,8 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (object->map()->unused_property_fields() == 0) {
+ if (details.type() == FIELD &&
+ object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ pop(scratch1); // Return address.
@@ -913,6 +931,12 @@
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ if (details.type() == CONSTANT_FUNCTION) {
+ ASSERT(value_reg.is(eax));
+ __ ret(0);
+ return;
+ }
+
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
@@ -1406,7 +1430,9 @@
// array for v8::Arguments::values_, handler for name and pointer
// to the values (it considered as smi in GC).
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
- const int kApiArgc = 2;
+ // Allocate space for opional callback address parameter in case
+ // CPU profiler is active.
+ const int kApiArgc = 2 + 1;
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
@@ -1422,7 +1448,13 @@
// garbage collection but instead return the allocation failure
// object.
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeAccessorGetter)
+ : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+
__ CallApiFunctionAndReturn(getter_address,
+ thunk_address,
+ ApiParameterOperand(2, returns_handle),
kStackSpace,
returns_handle,
6);
@@ -2752,7 +2784,7 @@
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
// ----------- S t a t e -------------
@@ -2935,7 +2967,7 @@
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name) {
Label miss;
@@ -2947,7 +2979,7 @@
// Compute the cell operand to use.
__ mov(scratch1(), Immediate(cell));
Operand cell_operand =
- FieldOperand(scratch1(), JSGlobalPropertyCell::kValueOffset);
+ FieldOperand(scratch1(), PropertyCell::kValueOffset);
// Check that the value in the cell is not the hole. If it is, this
// cell could have been deleted and reintroducing the global needs
@@ -3108,7 +3140,7 @@
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<GlobalObject> global,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
@@ -3119,7 +3151,7 @@
// Get the value from the cell.
if (Serializer::enabled()) {
__ mov(eax, Immediate(cell));
- __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
+ __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
} else {
__ mov(eax, Operand::ForCell(cell));
}
diff --git a/src/ic.cc b/src/ic.cc
index 095b614..d6e35a7 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -686,7 +686,7 @@
if (holder->IsGlobalObject()) {
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
- Handle<JSGlobalPropertyCell> cell(
+ Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
Handle<JSFunction> function(JSFunction::cast(cell->value()));
@@ -936,15 +936,7 @@
}
// Update inline cache and stub cache.
- if (FLAG_use_ic) {
- if (!object->IsJSObject()) {
- // TODO(jkummerow): It would be nice to support non-JSObjects in
- // UpdateCaches, then we wouldn't need to go generic here.
- set_target(*generic_stub());
- } else {
- UpdateCaches(&lookup, state, object, name);
- }
- }
+ if (FLAG_use_ic) UpdateCaches(&lookup, state, object, name);
PropertyAttributes attr;
if (lookup.IsInterceptor() || lookup.IsHandler()) {
@@ -1204,11 +1196,17 @@
Handle<Object> object,
Handle<String> name) {
// Bail out if the result is not cacheable.
- if (!lookup->IsCacheable()) return;
+ if (!lookup->IsCacheable()) {
+ set_target(*generic_stub());
+ return;
+ }
- // Loading properties from values is not common, so don't try to
- // deal with non-JS objects here.
- if (!object->IsJSObject()) return;
+ // TODO(jkummerow): It would be nice to support non-JSObjects in
+ // UpdateCaches, then we wouldn't need to go generic here.
+ if (!object->IsJSObject()) {
+ set_target(*generic_stub());
+ return;
+ }
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<Code> code;
@@ -1219,7 +1217,10 @@
code = pre_monomorphic_stub();
} else {
code = ComputeLoadHandler(lookup, receiver, name);
- if (code.is_null()) return;
+ if (code.is_null()) {
+ set_target(*generic_stub());
+ return;
+ }
}
PatchCache(state, kNonStrictMode, receiver, name, code);
@@ -1257,7 +1258,7 @@
case NORMAL:
if (holder->IsGlobalObject()) {
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
- Handle<JSGlobalPropertyCell> cell(
+ Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
return isolate()->stub_cache()->ComputeLoadGlobal(
name, receiver, global, cell, lookup->IsDontDelete());
@@ -1640,6 +1641,12 @@
IsUndeclaredGlobal(object)) {
// Strict mode doesn't allow setting non-existent global property.
return ReferenceError("not_defined", name);
+ } else if (FLAG_use_ic &&
+ (lookup.IsNormal() ||
+ (lookup.IsField() && lookup.CanHoldValue(value)))) {
+ Handle<Code> stub = strict_mode == kStrictMode
+ ? generic_stub_strict() : generic_stub();
+ set_target(*stub);
}
// Set the property.
@@ -1660,9 +1667,14 @@
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
- Handle<Code> code =
- ComputeStoreMonomorphic(lookup, strict_mode, receiver, name);
- if (code.is_null()) return;
+ Handle<Code> code = ComputeStoreMonomorphic(
+ lookup, strict_mode, receiver, name);
+ if (code.is_null()) {
+ Handle<Code> stub = strict_mode == kStrictMode
+ ? generic_stub_strict() : generic_stub();
+ set_target(*stub);
+ return;
+ }
PatchCache(state, strict_mode, receiver, name, code);
TRACE_IC("StoreIC", name, state, target());
@@ -1684,7 +1696,7 @@
// from the property cell. So the property must be directly on the
// global object.
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
- Handle<JSGlobalPropertyCell> cell(
+ Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
return isolate()->stub_cache()->ComputeStoreGlobal(
name, global, cell, strict_mode);
@@ -1733,7 +1745,7 @@
DescriptorArray* target_descriptors = transition->instance_descriptors();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
- if (details.type() != FIELD || details.attributes() != NONE) break;
+ if (details.type() == CALLBACKS || details.attributes() != NONE) break;
return isolate()->stub_cache()->ComputeStoreTransition(
name, receiver, lookup, transition, strict_mode);
@@ -2099,7 +2111,7 @@
DescriptorArray* target_descriptors = transition->instance_descriptors();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
- if (details.type() == FIELD && details.attributes() == NONE) {
+ if (details.type() != CALLBACKS && details.attributes() == NONE) {
return isolate()->stub_cache()->ComputeKeyedStoreTransition(
name, receiver, lookup, transition, strict_mode);
}
@@ -2408,17 +2420,34 @@
UnaryOpIC::State UnaryOpIC::ToState(TypeInfo type_info) {
switch (type_info) {
case UNINITIALIZED:
- return ::v8::internal::UNINITIALIZED;
+ return v8::internal::UNINITIALIZED;
case SMI:
case NUMBER:
return MONOMORPHIC;
case GENERIC:
- return ::v8::internal::GENERIC;
+ return v8::internal::GENERIC;
}
UNREACHABLE();
- return ::v8::internal::UNINITIALIZED;
+ return v8::internal::UNINITIALIZED;
}
+
+Handle<Type> UnaryOpIC::TypeInfoToType(TypeInfo type_info, Isolate* isolate) {
+ switch (type_info) {
+ case UNINITIALIZED:
+ return handle(Type::None(), isolate);
+ case SMI:
+ return handle(Type::Integer31(), isolate);
+ case NUMBER:
+ return handle(Type::Number(), isolate);
+ case GENERIC:
+ return handle(Type::Any(), isolate);
+ }
+ UNREACHABLE();
+ return handle(Type::Any(), isolate);
+}
+
+
UnaryOpIC::TypeInfo UnaryOpIC::GetTypeInfo(Handle<Object> operand) {
v8::internal::TypeInfo operand_type =
v8::internal::TypeInfo::FromValue(operand);
@@ -2489,6 +2518,46 @@
}
+Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type,
+ Isolate* isolate) {
+ switch (binary_type) {
+ case UNINITIALIZED:
+ return handle(Type::None(), isolate);
+ case SMI:
+ return handle(Type::Integer31(), isolate);
+ case INT32:
+ return handle(Type::Integer32(), isolate);
+ case NUMBER:
+ return handle(Type::Number(), isolate);
+ case ODDBALL:
+ return handle(Type::Optional(
+ handle(Type::Union(
+ handle(Type::Number(), isolate),
+ handle(Type::String(), isolate)), isolate)), isolate);
+ case STRING:
+ return handle(Type::String(), isolate);
+ case GENERIC:
+ return handle(Type::Any(), isolate);
+ }
+ UNREACHABLE();
+ return handle(Type::Any(), isolate);
+}
+
+
+void BinaryOpIC::StubInfoToType(int minor_key,
+ Handle<Type>* left,
+ Handle<Type>* right,
+ Handle<Type>* result,
+ Isolate* isolate) {
+ TypeInfo left_typeinfo, right_typeinfo, result_typeinfo;
+ BinaryOpStub::decode_types_from_minor_key(
+ minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo);
+ *left = TypeInfoToType(left_typeinfo, isolate);
+ *right = TypeInfoToType(right_typeinfo, isolate);
+ *result = TypeInfoToType(result_typeinfo, isolate);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
ASSERT(args.length() == 4);
@@ -2802,45 +2871,60 @@
}
-static CompareIC::State InputState(CompareIC::State old_state,
- Handle<Object> value) {
+void CompareIC::StubInfoToType(int stub_minor_key,
+ Handle<Type>* left_type,
+ Handle<Type>* right_type,
+ Handle<Type>* overall_type,
+ Handle<Map> map,
+ Isolate* isolate) {
+ State left_state, right_state, handler_state;
+ ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
+ &handler_state, NULL);
+ *left_type = StateToType(isolate, left_state);
+ *right_type = StateToType(isolate, right_state);
+ *overall_type = StateToType(isolate, handler_state, map);
+}
+
+
+CompareIC::State CompareIC::NewInputState(State old_state,
+ Handle<Object> value) {
switch (old_state) {
- case CompareIC::UNINITIALIZED:
- if (value->IsSmi()) return CompareIC::SMI;
- if (value->IsHeapNumber()) return CompareIC::NUMBER;
- if (value->IsInternalizedString()) return CompareIC::INTERNALIZED_STRING;
- if (value->IsString()) return CompareIC::STRING;
- if (value->IsSymbol()) return CompareIC::UNIQUE_NAME;
- if (value->IsJSObject()) return CompareIC::OBJECT;
+ case UNINITIALIZED:
+ if (value->IsSmi()) return SMI;
+ if (value->IsHeapNumber()) return NUMBER;
+ if (value->IsInternalizedString()) return INTERNALIZED_STRING;
+ if (value->IsString()) return STRING;
+ if (value->IsSymbol()) return UNIQUE_NAME;
+ if (value->IsJSObject()) return OBJECT;
break;
- case CompareIC::SMI:
- if (value->IsSmi()) return CompareIC::SMI;
- if (value->IsHeapNumber()) return CompareIC::NUMBER;
+ case SMI:
+ if (value->IsSmi()) return SMI;
+ if (value->IsHeapNumber()) return NUMBER;
break;
- case CompareIC::NUMBER:
- if (value->IsNumber()) return CompareIC::NUMBER;
+ case NUMBER:
+ if (value->IsNumber()) return NUMBER;
break;
- case CompareIC::INTERNALIZED_STRING:
- if (value->IsInternalizedString()) return CompareIC::INTERNALIZED_STRING;
- if (value->IsString()) return CompareIC::STRING;
- if (value->IsSymbol()) return CompareIC::UNIQUE_NAME;
+ case INTERNALIZED_STRING:
+ if (value->IsInternalizedString()) return INTERNALIZED_STRING;
+ if (value->IsString()) return STRING;
+ if (value->IsSymbol()) return UNIQUE_NAME;
break;
- case CompareIC::STRING:
- if (value->IsString()) return CompareIC::STRING;
+ case STRING:
+ if (value->IsString()) return STRING;
break;
- case CompareIC::UNIQUE_NAME:
- if (value->IsUniqueName()) return CompareIC::UNIQUE_NAME;
+ case UNIQUE_NAME:
+ if (value->IsUniqueName()) return UNIQUE_NAME;
break;
- case CompareIC::OBJECT:
- if (value->IsJSObject()) return CompareIC::OBJECT;
+ case OBJECT:
+ if (value->IsJSObject()) return OBJECT;
break;
- case CompareIC::GENERIC:
+ case GENERIC:
break;
- case CompareIC::KNOWN_OBJECT:
+ case KNOWN_OBJECT:
UNREACHABLE();
break;
}
- return CompareIC::GENERIC;
+ return GENERIC;
}
@@ -2913,8 +2997,8 @@
State previous_left, previous_right, previous_state;
ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
&previous_right, &previous_state, NULL);
- State new_left = InputState(previous_left, x);
- State new_right = InputState(previous_right, y);
+ State new_left = NewInputState(previous_left, x);
+ State new_right = NewInputState(previous_right, y);
State state = TargetState(previous_state, previous_left, previous_right,
HasInlinedSmiCode(address()), x, y);
ICCompareStub stub(op_, new_left, new_right, state);
diff --git a/src/ic.h b/src/ic.h
index fc869ad..829c6b1 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -511,8 +511,8 @@
static void GenerateMegamorphic(MacroAssembler* masm,
StrictModeFlag strict_mode);
static void GenerateNormal(MacroAssembler* masm);
- static void GenerateGlobalProxy(MacroAssembler* masm,
- StrictModeFlag strict_mode);
+ static void GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* Store(
State state,
@@ -532,6 +532,12 @@
virtual Handle<Code> megamorphic_stub_strict() {
return isolate()->builtins()->StoreIC_Megamorphic_Strict();
}
+ virtual Handle<Code> generic_stub() const {
+ return isolate()->builtins()->StoreIC_Generic();
+ }
+ virtual Handle<Code> generic_stub_strict() const {
+ return isolate()->builtins()->StoreIC_Generic_Strict();
+ }
virtual Handle<Code> global_proxy_stub() {
return isolate()->builtins()->StoreIC_GlobalProxy();
}
@@ -684,6 +690,8 @@
GENERIC
};
+ static Handle<Type> TypeInfoToType(TypeInfo info, Isolate* isolate);
+
explicit UnaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
void patch(Code* code);
@@ -711,6 +719,12 @@
GENERIC
};
+ static void StubInfoToType(int minor_key,
+ Handle<Type>* left,
+ Handle<Type>* right,
+ Handle<Type>* result,
+ Isolate* isolate);
+
explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
void patch(Code* code);
@@ -718,6 +732,9 @@
static const char* GetName(TypeInfo type_info);
static State ToState(TypeInfo type_info);
+
+ private:
+ static Handle<Type> TypeInfoToType(TypeInfo binary_type, Isolate* isolate);
};
@@ -741,8 +758,18 @@
GENERIC
};
- static Handle<Type> StateToType(
- Isolate* isolate, State state, Handle<Map> map = Handle<Map>());
+ static State NewInputState(State old_state, Handle<Object> value);
+
+ static Handle<Type> StateToType(Isolate* isolate,
+ State state,
+ Handle<Map> map = Handle<Map>());
+
+ static void StubInfoToType(int stub_minor_key,
+ Handle<Type>* left_type,
+ Handle<Type>* right_type,
+ Handle<Type>* overall_type,
+ Handle<Map> map,
+ Isolate* isolate);
CompareIC(Isolate* isolate, Token::Value op)
: IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
diff --git a/src/lithium.h b/src/lithium.h
index 170e5c8..ab34453 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -527,6 +527,7 @@
deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
translation_index_(-1),
ast_id_(ast_id),
+ translation_size_(value_count),
parameter_count_(parameter_count),
pc_offset_(-1),
values_(value_count, zone),
@@ -544,6 +545,7 @@
int deoptimization_index() const { return deoptimization_index_; }
int translation_index() const { return translation_index_; }
BailoutId ast_id() const { return ast_id_; }
+ int translation_size() const { return translation_size_; }
int parameter_count() const { return parameter_count_; }
int pc_offset() const { return pc_offset_; }
LOperand** spilled_registers() const { return spilled_registers_; }
@@ -553,6 +555,7 @@
const ZoneList<LOperand*>* values() const { return &values_; }
LEnvironment* outer() const { return outer_; }
HEnterInlined* entry() { return entry_; }
+ Zone* zone() const { return zone_; }
void AddValue(LOperand* operand,
Representation representation,
@@ -560,11 +563,11 @@
values_.Add(operand, zone());
if (representation.IsSmiOrTagged()) {
ASSERT(!is_uint32);
- is_tagged_.Add(values_.length() - 1);
+ is_tagged_.Add(values_.length() - 1, zone());
}
if (is_uint32) {
- is_uint32_.Add(values_.length() - 1);
+ is_uint32_.Add(values_.length() - 1, zone());
}
}
@@ -596,8 +599,6 @@
void PrintTo(StringStream* stream);
- Zone* zone() const { return zone_; }
-
private:
Handle<JSFunction> closure_;
FrameType frame_type_;
@@ -605,11 +606,15 @@
int deoptimization_index_;
int translation_index_;
BailoutId ast_id_;
+ int translation_size_;
int parameter_count_;
int pc_offset_;
+
+ // Value array: [parameters] [locals] [expression stack] [de-materialized].
+ // |>--------- translation_size ---------<|
ZoneList<LOperand*> values_;
- BitVector is_tagged_;
- BitVector is_uint32_;
+ GrowableBitVector is_tagged_;
+ GrowableBitVector is_uint32_;
// Allocation index indexed arrays of spill slot operands for registers
// that are also in spill slots at an OSR entry. NULL for environments
@@ -619,7 +624,6 @@
LEnvironment* outer_;
HEnterInlined* entry_;
-
Zone* zone_;
};
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 0501ccf..c06bfd7 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1010,8 +1010,9 @@
MarkBit code_mark = Marking::MarkBitFrom(code);
if (!code_mark.Get()) {
if (FLAG_trace_code_flushing && shared->is_compiled()) {
- SmartArrayPointer<char> name = shared->DebugName()->ToCString();
- PrintF("[code-flushing clears: %s - age: %d]\n", *name, code->GetAge());
+ PrintF("[code-flushing clears: ");
+ shared->ShortPrint();
+ PrintF(" - age: %d]\n", code->GetAge());
}
shared->set_code(lazy_compile);
candidate->set_code(lazy_compile);
@@ -1051,8 +1052,9 @@
MarkBit code_mark = Marking::MarkBitFrom(code);
if (!code_mark.Get()) {
if (FLAG_trace_code_flushing && candidate->is_compiled()) {
- SmartArrayPointer<char> name = candidate->DebugName()->ToCString();
- PrintF("[code-flushing clears: %s - age: %d]\n", *name, code->GetAge());
+ PrintF("[code-flushing clears: ");
+ candidate->ShortPrint();
+ PrintF(" - age: %d]\n", code->GetAge());
}
candidate->set_code(lazy_compile);
}
@@ -1093,7 +1095,7 @@
continue;
}
- // Update and record the context slot in the optimizled code map.
+ // Update and record the context slot in the optimized code map.
Object** context_slot = HeapObject::RawField(code_map,
FixedArray::OffsetOfElementAt(new_length));
code_map->set(new_length++, code_map->get(i + kContextOffset));
@@ -1138,8 +1140,9 @@
isolate_->heap()->incremental_marking()->RecordWrites(shared_info);
if (FLAG_trace_code_flushing) {
- SmartArrayPointer<char> name = shared_info->DebugName()->ToCString();
- PrintF("[code-flushing abandons function-info: %s]\n", *name);
+ PrintF("[code-flushing abandons function-info: ");
+ shared_info->ShortPrint();
+ PrintF("]\n");
}
SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
@@ -1174,8 +1177,9 @@
isolate_->heap()->incremental_marking()->RecordWrites(function->shared());
if (FLAG_trace_code_flushing) {
- SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
- PrintF("[code-flushing abandons closure: %s]\n", *name);
+ PrintF("[code-flushing abandons closure: ");
+ function->shared()->ShortPrint();
+ PrintF("]\n");
}
JSFunction* candidate = jsfunction_candidates_head_;
@@ -1209,8 +1213,9 @@
isolate_->heap()->incremental_marking()->RecordWrites(code_map_holder);
if (FLAG_trace_code_flushing) {
- SmartArrayPointer<char> name = code_map_holder->DebugName()->ToCString();
- PrintF("[code-flushing abandons code-map: %s]\n", *name);
+ PrintF("[code-flushing abandons code-map: ");
+ code_map_holder->ShortPrint();
+ PrintF("]\n");
}
SharedFunctionInfo* holder = optimized_code_map_holder_head_;
@@ -1495,15 +1500,13 @@
FIXED_ARRAY_TYPE) return;
// Make sure this is a RegExp that actually contains code.
- if (re->TypeTagUnchecked() != JSRegExp::IRREGEXP) return;
+ if (re->TypeTag() != JSRegExp::IRREGEXP) return;
- Object* code = re->DataAtUnchecked(JSRegExp::code_index(is_ascii));
+ Object* code = re->DataAt(JSRegExp::code_index(is_ascii));
if (!code->IsSmi() &&
HeapObject::cast(code)->map()->instance_type() == CODE_TYPE) {
// Save a copy that can be reinstated if we need the code again.
- re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
- code,
- heap);
+ re->SetDataAt(JSRegExp::saved_code_index(is_ascii), code);
// Saving a copy might create a pointer into compaction candidate
// that was not observed by marker. This might happen if JSRegExp data
@@ -1515,9 +1518,8 @@
RecordSlot(slot, slot, code);
// Set a number in the 0-255 range to guarantee no smi overflow.
- re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
- Smi::FromInt(heap->sweep_generation() & 0xff),
- heap);
+ re->SetDataAt(JSRegExp::code_index(is_ascii),
+ Smi::FromInt(heap->sweep_generation() & 0xff));
} else if (code->IsSmi()) {
int value = Smi::cast(code)->value();
// The regexp has not been compiled yet or there was a compilation error.
@@ -1528,12 +1530,10 @@
// Check if we should flush now.
if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) & 0xff)) {
- re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
- Smi::FromInt(JSRegExp::kUninitializedValue),
- heap);
- re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
- Smi::FromInt(JSRegExp::kUninitializedValue),
- heap);
+ re->SetDataAt(JSRegExp::code_index(is_ascii),
+ Smi::FromInt(JSRegExp::kUninitializedValue));
+ re->SetDataAt(JSRegExp::saved_code_index(is_ascii),
+ Smi::FromInt(JSRegExp::kUninitializedValue));
}
}
}
@@ -2267,13 +2267,13 @@
heap()->property_cell_space());
HeapObject* cell;
while ((cell = js_global_property_cell_iterator.Next()) != NULL) {
- ASSERT(cell->IsJSGlobalPropertyCell());
+ ASSERT(cell->IsPropertyCell());
if (IsMarked(cell)) {
- int offset = JSGlobalPropertyCell::kValueOffset;
+ int offset = PropertyCell::kValueOffset;
MarkCompactMarkingVisitor::VisitPointer(
heap(),
reinterpret_cast<Object**>(cell->address() + offset));
- offset = JSGlobalPropertyCell::kTypeOffset;
+ offset = PropertyCell::kTypeOffset;
MarkCompactMarkingVisitor::VisitPointer(
heap(),
reinterpret_cast<Object**>(cell->address() + offset));
@@ -2448,7 +2448,7 @@
// This map is used for inobject slack tracking and has been detached
// from SharedFunctionInfo during the mark phase.
// Since it survived the GC, reattach it now.
- map->unchecked_constructor()->shared()->AttachInitialMap(map);
+ JSFunction::cast(map->constructor())->shared()->AttachInitialMap(map);
}
ClearNonLivePrototypeTransitions(map);
@@ -2479,13 +2479,11 @@
int proto_index = proto_offset + new_number_of_transitions * step;
int map_index = map_offset + new_number_of_transitions * step;
if (new_number_of_transitions != i) {
- prototype_transitions->set_unchecked(
- heap_,
+ prototype_transitions->set(
proto_index,
prototype,
UPDATE_WRITE_BARRIER);
- prototype_transitions->set_unchecked(
- heap_,
+ prototype_transitions->set(
map_index,
cached_map,
SKIP_WRITE_BARRIER);
@@ -3431,14 +3429,14 @@
for (HeapObject* cell = js_global_property_cell_iterator.Next();
cell != NULL;
cell = js_global_property_cell_iterator.Next()) {
- if (cell->IsJSGlobalPropertyCell()) {
+ if (cell->IsPropertyCell()) {
Address value_address =
reinterpret_cast<Address>(cell) +
- (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
+ (PropertyCell::kValueOffset - kHeapObjectTag);
updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
Address type_address =
reinterpret_cast<Address>(cell) +
- (JSGlobalPropertyCell::kTypeOffset - kHeapObjectTag);
+ (PropertyCell::kTypeOffset - kHeapObjectTag);
updating_visitor.VisitPointer(reinterpret_cast<Object**>(type_address));
}
}
diff --git a/src/mips/OWNERS b/src/mips/OWNERS
index 3cb222c..38473b5 100644
--- a/src/mips/OWNERS
+++ b/src/mips/OWNERS
@@ -1 +1,2 @@
plind44@gmail.com
+gergely@homejinni.com
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 5c8d08c..cb59779 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -2488,47 +2488,36 @@
UNREACHABLE();
}
- if (op_ != Token::DIV) {
- // These operations produce an integer result.
- // Try to return a smi if we can.
- // Otherwise return a heap number if allowed, or jump to type
- // transition.
-
+ if (result_type_ <= BinaryOpIC::INT32) {
Register except_flag = scratch2;
- __ EmitFPUTruncate(kRoundToZero,
+ const FPURoundingMode kRoundingMode = op_ == Token::DIV ?
+ kRoundToMinusInf : kRoundToZero;
+ const CheckForInexactConversion kConversion = op_ == Token::DIV ?
+ kCheckForInexactConversion : kDontCheckForInexactConversion;
+ __ EmitFPUTruncate(kRoundingMode,
scratch1,
f10,
at,
f16,
- except_flag);
-
- if (result_type_ <= BinaryOpIC::INT32) {
- // If except_flag != 0, result does not fit in a 32-bit integer.
- __ Branch(&transition, ne, except_flag, Operand(zero_reg));
- }
-
- // Check if the result fits in a smi.
- __ Addu(scratch2, scratch1, Operand(0x40000000));
- // If not try to return a heap number.
+ except_flag,
+ kConversion);
+ // If except_flag != 0, result does not fit in a 32-bit integer.
+ __ Branch(&transition, ne, except_flag, Operand(zero_reg));
+ // Try to tag the result as a Smi, return heap number on overflow.
+ __ SmiTagCheckOverflow(scratch1, scratch1, scratch2);
__ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg));
- // Check for minus zero. Return heap number for minus zero if
- // double results are allowed; otherwise transition.
+ // Check for minus zero, transition in that case (because we need
+ // to return a heap number).
Label not_zero;
+ ASSERT(kSmiTag == 0);
__ Branch(¬_zero, ne, scratch1, Operand(zero_reg));
__ mfc1(scratch2, f11);
__ And(scratch2, scratch2, HeapNumber::kSignMask);
- __ Branch(result_type_ <= BinaryOpIC::INT32 ? &transition
- : &return_heap_number,
- ne,
- scratch2,
- Operand(zero_reg));
+ __ Branch(&transition, ne, scratch2, Operand(zero_reg));
__ bind(¬_zero);
- // Tag the result and return.
__ Ret(USE_DELAY_SLOT);
- __ SmiTag(v0, scratch1); // SmiTag emits one instruction.
- } else {
- // DIV just falls through to allocating a heap number.
+ __ mov(v0, scratch1);
}
__ bind(&return_heap_number);
@@ -6912,13 +6901,6 @@
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
- ExternalReference function) {
- __ li(t9, Operand(function));
- this->GenerateCall(masm, t9);
-}
-
-
-void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
Register target) {
__ Move(t9, target);
__ AssertStackIsAligned();
@@ -7500,10 +7482,10 @@
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : element value to store
- // -- a1 : array literal
- // -- a2 : map of array literal
// -- a3 : element index as smi
- // -- t0 : array literal index in function as smi
+ // -- sp[0] : array literal index in function as smi
+ // -- sp[4] : array literal
+ // clobbers a1, a2, t0
// -----------------------------------
Label element_done;
@@ -7512,6 +7494,11 @@
Label slow_elements;
Label fast_elements;
+ // Get array literal index, array literal and its map.
+ __ lw(t0, MemOperand(sp, 0 * kPointerSize));
+ __ lw(a1, MemOperand(sp, 1 * kPointerSize));
+ __ lw(a2, FieldMemOperand(a1, JSObject::kMapOffset));
+
__ CheckFastElements(a2, t1, &double_elements);
// Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
__ JumpIfSmi(a0, &smi_element);
@@ -7790,7 +7777,7 @@
Label no_info, switch_ready;
// Get the elements kind and case on that.
__ Branch(&no_info, eq, a2, Operand(undefined_sentinel));
- __ lw(a3, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+ __ lw(a3, FieldMemOperand(a2, PropertyCell::kValueOffset));
__ JumpIfNotSmi(a3, &no_info);
__ SmiUntag(a3);
__ jmp(&switch_ready);
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index ec7d147..bf5db10 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -599,8 +599,6 @@
public:
DirectCEntryStub() {}
void Generate(MacroAssembler* masm);
- void GenerateCall(MacroAssembler* masm,
- ExternalReference function);
void GenerateCall(MacroAssembler* masm, Register target);
private:
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index a16e478..df83019 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -363,7 +363,7 @@
ASSERT(back_edge_target->is_bound());
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
__ slt(at, a3, zero_reg);
@@ -406,7 +406,7 @@
} else if (FLAG_weighted_back_edges) {
int distance = masm_->pc_offset();
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
Label ok;
@@ -1840,7 +1840,8 @@
}
if (!result_saved) {
- __ push(v0);
+ __ push(v0); // array literal
+ __ Push(Smi::FromInt(expr->literal_index()));
result_saved = true;
}
@@ -1848,7 +1849,7 @@
if (IsFastObjectElementsKind(constant_elements_kind)) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ lw(t2, MemOperand(sp)); // Copy of array literal.
+ __ lw(t2, MemOperand(sp, kPointerSize)); // Copy of array literal.
__ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset));
__ sw(result_register(), FieldMemOperand(a1, offset));
// Update the write barrier for the array store.
@@ -1856,10 +1857,7 @@
kRAHasBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
} else {
- __ lw(a1, MemOperand(sp)); // Copy of array literal.
- __ lw(a2, FieldMemOperand(a1, JSObject::kMapOffset));
__ li(a3, Operand(Smi::FromInt(i)));
- __ li(t0, Operand(Smi::FromInt(expr->literal_index())));
__ mov(a0, result_register());
StoreArrayLiteralElementStub stub;
__ CallStub(&stub);
@@ -1868,6 +1866,7 @@
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
if (result_saved) {
+ __ Pop(); // literal index
context()->PlugTOS();
} else {
context()->Plug(v0);
@@ -2042,23 +2041,21 @@
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
__ Branch(&l_next);
- // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
+ // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
__ bind(&l_catch);
__ mov(a0, v0);
handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+ __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ push(a3); // iter
__ push(a0); // exception
- __ mov(a0, a3); // iter
- __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
- Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize();
- CallIC(throw_ic); // iter.throw in a0
- __ mov(a0, v0);
__ jmp(&l_call);
- // try { received = yield result.value }
+ // try { received = %yield result }
+ // Shuffle the received result above a try handler and yield it without
+ // re-boxing.
__ bind(&l_try);
- EmitCreateIteratorResult(false); // pop and box to v0
+ __ pop(a0); // result
__ PushTryHandler(StackHandler::CATCH, expr->index());
const int handler_size = StackHandlerConstants::kSize;
__ push(a0); // result
@@ -2076,45 +2073,23 @@
__ bind(&l_resume); // received in a0
__ PopTryHandler();
- // receiver = iter; f = iter.next; arg = received;
+ // receiver = iter; f = 'next'; arg = received;
__ bind(&l_next);
+ __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ push(a3); // iter
__ push(a0); // received
- __ mov(a0, a3); // iter
- __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
- Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize();
- CallIC(next_ic); // iter.next in a0
- __ mov(a0, v0);
- // result = f.call(receiver, arg);
+ // result = receiver[f](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);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1);
+ CallIC(ic);
__ 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;
+ // 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
__ LoadRoot(a2, Heap::kdone_stringRootIndex); // "done"
Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(done_ic); // result.done in v0
@@ -2124,7 +2099,10 @@
__ Branch(&l_try, eq, v0, Operand(zero_reg));
// result.value
- __ pop(v0); // result.value
+ __ pop(a0); // result
+ __ LoadRoot(a2, Heap::kvalue_stringRootIndex); // "value"
+ Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
+ CallIC(value_ic); // result.value in v0
context()->DropAndPlug(2, v0); // drop iter and g
break;
}
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index c1b4e1e..b30ee31 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1588,8 +1588,8 @@
}
-void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
- StrictModeFlag strict_mode) {
+void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- a0 : value
// -- a1 : receiver
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index c256646..12f4d1a 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -561,27 +561,15 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* pushed_arguments_index,
- int* pushed_arguments_count) {
+ Translation* translation) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
- int translation_size = environment->values()->length();
+ int translation_size = environment->translation_size();
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- // Function parameters are arguments to the outermost environment. The
- // arguments index points to the first element of a sequence of tagged
- // values on the stack that represent the arguments. This needs to be
- // kept in sync with the LArgumentsElements implementation.
- *pushed_arguments_index = -environment->parameter_count();
- *pushed_arguments_count = environment->parameter_count();
-
- WriteTranslation(environment->outer(),
- translation,
- pushed_arguments_index,
- pushed_arguments_count);
+ WriteTranslation(environment->outer(), translation);
bool has_closure_id = !info()->closure().is_null() &&
!info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
@@ -613,23 +601,6 @@
break;
}
- // Inlined frames which push their arguments cause the index to be
- // bumped and another stack area to be used for materialization,
- // otherwise actual argument values are unknown for inlined frames.
- bool arguments_known = true;
- int arguments_index = *pushed_arguments_index;
- int arguments_count = *pushed_arguments_count;
- if (environment->entry() != NULL) {
- arguments_known = environment->entry()->arguments_pushed();
- arguments_index = arguments_index < 0
- ? GetStackSlotCount() : arguments_index + arguments_count;
- arguments_count = environment->entry()->arguments_count() + 1;
- if (environment->entry()->arguments_pushed()) {
- *pushed_arguments_index = arguments_index;
- *pushed_arguments_count = arguments_count;
- }
- }
-
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -641,10 +612,7 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
@@ -653,20 +621,36 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false,
- arguments_known,
- arguments_index,
- arguments_count);
+ false);
}
}
+ // TODO(mstarzinger): Introduce marker operands to indicate that this value
+ // is not present and must be reconstructed from the deoptimizer. Currently
+ // this is only used for the arguments object.
+ if (value == NULL) {
+ int arguments_count = environment->values()->length() - translation_size;
+ translation->BeginArgumentsObject(arguments_count);
+ for (int i = 0; i < arguments_count; ++i) {
+ LOperand* value = environment->values()->at(translation_size + i);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsRegister() ||
+ environment->spilled_registers()[value->index()] == NULL);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsDoubleRegister() ||
+ environment->spilled_double_registers()[value->index()] == NULL);
+ AddToTranslation(translation,
+ value,
+ environment->HasTaggedValueAt(translation_size + i),
+ environment->HasUint32ValueAt(translation_size + i));
+ }
+ continue;
+ }
+
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
}
}
@@ -674,17 +658,8 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count) {
- if (op == NULL) {
- // TODO(twuerthinger): Introduce marker operands to indicate that this value
- // is not present and must be reconstructed from the deoptimizer. Currently
- // this is only used for the arguments object.
- translation->StoreArgumentsObject(
- arguments_known, arguments_index, arguments_count);
- } else if (op->IsStackSlot()) {
+ bool is_uint32) {
+ if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else if (is_uint32) {
@@ -779,8 +754,6 @@
int frame_count = 0;
int jsframe_count = 0;
- int args_index = 0;
- int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@@ -788,7 +761,7 @@
}
}
Translation translation(&translations_, frame_count, jsframe_count, zone());
- WriteTranslation(environment, &translation, &args_index, &args_count);
+ WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
@@ -1203,6 +1176,109 @@
}
+void LCodeGen::EmitSignedIntegerDivisionByConstant(
+ Register result,
+ Register dividend,
+ int32_t divisor,
+ Register remainder,
+ Register scratch,
+ LEnvironment* environment) {
+ ASSERT(!AreAliased(dividend, scratch, at, no_reg));
+ ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
+
+ uint32_t divisor_abs = abs(divisor);
+
+ int32_t power_of_2_factor =
+ CompilerIntrinsics::CountTrailingZeros(divisor_abs);
+
+ switch (divisor_abs) {
+ case 0:
+ DeoptimizeIf(al, environment);
+ return;
+
+ case 1:
+ if (divisor > 0) {
+ __ Move(result, dividend);
+ } else {
+ __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch);
+ DeoptimizeIf(lt, environment, scratch, Operand(zero_reg));
+ }
+ // Compute the remainder.
+ __ Move(remainder, zero_reg);
+ return;
+
+ default:
+ if (IsPowerOf2(divisor_abs)) {
+ // Branch and condition free code for integer division by a power
+ // of two.
+ int32_t power = WhichPowerOf2(divisor_abs);
+ if (power > 1) {
+ __ sra(scratch, dividend, power - 1);
+ }
+ __ srl(scratch, scratch, 32 - power);
+ __ Addu(scratch, dividend, Operand(scratch));
+ __ sra(result, scratch, power);
+ // Negate if necessary.
+ // We don't need to check for overflow because the case '-1' is
+ // handled separately.
+ if (divisor < 0) {
+ ASSERT(divisor != -1);
+ __ Subu(result, zero_reg, Operand(result));
+ }
+ // Compute the remainder.
+ if (divisor > 0) {
+ __ sll(scratch, result, power);
+ __ Subu(remainder, dividend, Operand(scratch));
+ } else {
+ __ sll(scratch, result, power);
+ __ Addu(remainder, dividend, Operand(scratch));
+ }
+ return;
+ } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) {
+ // Use magic numbers for a few specific divisors.
+ // Details and proofs can be found in:
+ // - Hacker's Delight, Henry S. Warren, Jr.
+ // - The PowerPC Compiler Writer's Guide
+ // and probably many others.
+ //
+ // We handle
+ // <divisor with magic numbers> * <power of 2>
+ // but not
+ // <divisor with magic numbers> * <other divisor with magic numbers>
+ DivMagicNumbers magic_numbers =
+ DivMagicNumberFor(divisor_abs >> power_of_2_factor);
+ // Branch and condition free code for integer division by a power
+ // of two.
+ const int32_t M = magic_numbers.M;
+ const int32_t s = magic_numbers.s + power_of_2_factor;
+
+ __ li(scratch, Operand(M));
+ __ mult(dividend, scratch);
+ __ mfhi(scratch);
+ if (M < 0) {
+ __ Addu(scratch, scratch, Operand(dividend));
+ }
+ if (s > 0) {
+ __ sra(scratch, scratch, s);
+ __ mov(scratch, scratch);
+ }
+ __ srl(at, dividend, 31);
+ __ Addu(result, scratch, Operand(at));
+ if (divisor < 0) __ Subu(result, zero_reg, Operand(result));
+ // Compute the remainder.
+ __ li(scratch, Operand(divisor));
+ __ Mul(scratch, result, Operand(scratch));
+ __ Subu(remainder, dividend, Operand(scratch));
+ } else {
+ __ li(scratch, Operand(divisor));
+ __ div(dividend, scratch);
+ __ mfhi(remainder);
+ __ mflo(result);
+ }
+ }
+}
+
+
void LCodeGen::DoDivI(LDivI* instr) {
const Register left = ToRegister(instr->left());
const Register right = ToRegister(instr->right());
@@ -1253,6 +1329,70 @@
}
+void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
+ const Register result = ToRegister(instr->result());
+ const Register left = ToRegister(instr->left());
+ const Register remainder = ToRegister(instr->temp());
+ const Register scratch = scratch0();
+
+ if (instr->right()->IsConstantOperand()) {
+ Label done;
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
+ if (divisor < 0) {
+ DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
+ }
+ EmitSignedIntegerDivisionByConstant(result,
+ left,
+ divisor,
+ remainder,
+ scratch,
+ instr->environment());
+ // We performed a truncating division. Correct the result if necessary.
+ __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
+ __ Xor(scratch , remainder, Operand(divisor));
+ __ Branch(&done, ge, scratch, Operand(zero_reg));
+ __ Subu(result, result, Operand(1));
+ __ bind(&done);
+ } else {
+ Label done;
+ const Register right = ToRegister(instr->right());
+
+ // On MIPS div is asynchronous - it will run in the background while we
+ // check for special cases.
+ __ div(left, right);
+
+ // Check for x / 0.
+ DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
+
+ // Check for (0 / -x) that will produce negative zero.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label left_not_zero;
+ __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
+ DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
+ __ bind(&left_not_zero);
+ }
+
+ // Check for (kMinInt / -1).
+ if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ Label left_not_min_int;
+ __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
+ DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
+ __ bind(&left_not_min_int);
+ }
+
+ __ mfhi(remainder);
+ __ mflo(result);
+
+ // We performed a truncating division. Correct the result if necessary.
+ __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
+ __ Xor(scratch , remainder, Operand(right));
+ __ Branch(&done, ge, scratch, Operand(zero_reg));
+ __ Subu(result, result, Operand(1));
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoMulI(LMulI* instr) {
Register scratch = scratch0();
Register result = ToRegister(instr->result());
@@ -2468,7 +2608,7 @@
// the cached map.
Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
__ li(at, Operand(Handle<Object>(cell)));
- __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset));
+ __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset));
__ Branch(&cache_miss, ne, map, Operand(at));
// We use Factory::the_hole_value() on purpose instead of loading from the
// root array to force relocation to be able to later patch
@@ -5044,7 +5184,7 @@
AllowDeferredHandleDereference smi_check;
if (isolate()->heap()->InNewSpace(*target)) {
Register reg = ToRegister(instr->value());
- Handle<Cell> cell = isolate()->factory()->NewJSGlobalPropertyCell(target);
+ Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target);
__ li(at, Operand(Handle<Object>(cell)));
__ lw(at, FieldMemOperand(at, Cell::kValueOffset));
DeoptimizeIf(ne, instr->environment(), reg,
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index ee01383..1c99cf9 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -169,10 +169,7 @@
int additional_offset);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* arguments_index,
- int* arguments_count);
+ void WriteTranslation(LEnvironment* environment, Translation* translation);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -295,10 +292,7 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count);
+ bool is_uint32);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
@@ -390,6 +384,17 @@
Register source,
int* offset,
AllocationSiteMode mode);
+ // Emit optimized code for integer division.
+ // Inputs are signed.
+ // All registers are clobbered.
+ // If 'remainder' is no_reg, it is not computed.
+ void EmitSignedIntegerDivisionByConstant(Register result,
+ Register dividend,
+ int32_t divisor,
+ Register remainder,
+ Register scratch,
+ LEnvironment* environment);
+
void EnsureSpaceForLazyDeopt();
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index ad39c61..1b94332 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -933,7 +933,7 @@
BailoutId ast_id = hydrogen_env->ast_id();
ASSERT(!ast_id.IsNone() ||
hydrogen_env->frame_type() != JS_FUNCTION);
- int value_count = hydrogen_env->length();
+ int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
LEnvironment* result = new(zone()) LEnvironment(
hydrogen_env->closure(),
hydrogen_env->frame_type(),
@@ -944,13 +944,15 @@
outer,
hydrogen_env->entry(),
zone());
+ bool needs_arguments_object_materialization = false;
int argument_index = *argument_index_accumulator;
- for (int i = 0; i < value_count; ++i) {
+ for (int i = 0; i < hydrogen_env->length(); ++i) {
if (hydrogen_env->is_special_index(i)) continue;
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
+ needs_arguments_object_materialization = true;
op = NULL;
} else if (value->IsPushArgument()) {
op = new(zone()) LArgument(argument_index++);
@@ -962,6 +964,21 @@
value->CheckFlag(HInstruction::kUint32));
}
+ if (needs_arguments_object_materialization) {
+ HArgumentsObject* arguments = hydrogen_env->entry() == NULL
+ ? graph()->GetArgumentsObject()
+ : hydrogen_env->entry()->arguments_object();
+ ASSERT(arguments->IsLinked());
+ for (int i = 1; i < arguments->arguments_count(); ++i) {
+ HValue* value = arguments->arguments_values()->at(i);
+ ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
+ LOperand* op = UseAny(value);
+ result->AddValue(op,
+ value->representation(),
+ value->CheckFlag(HInstruction::kUint32));
+ }
+ }
+
if (hydrogen_env->frame_type() == JS_FUNCTION) {
*argument_index_accumulator = argument_index;
}
@@ -1342,27 +1359,69 @@
if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else if (instr->representation().IsInteger32()) {
- // TODO(1042) The fixed register allocation
- // is needed because we call TypeRecordingBinaryOpStub from
- // the generated code, which requires registers a0
- // and a1 to be used. We should remove that
- // when we provide a native implementation.
- LOperand* dividend = UseFixed(instr->left(), a0);
- LOperand* divisor = UseFixed(instr->right(), a1);
- return AssignEnvironment(AssignPointerMap(
- DefineFixed(new(zone()) LDivI(dividend, divisor), v0)));
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegister(instr->right());
+ LDivI* div = new(zone()) LDivI(dividend, divisor);
+ return AssignEnvironment(DefineAsRegister(div));
} else {
return DoArithmeticT(Token::DIV, instr);
}
}
-LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
- UNIMPLEMENTED();
+bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
+ uint32_t divisor_abs = abs(divisor);
+ // Dividing by 0, 1, and powers of 2 is easy.
+ // Note that IsPowerOf2(0) returns true;
+ ASSERT(IsPowerOf2(0) == true);
+ if (IsPowerOf2(divisor_abs)) return true;
+
+ // We have magic numbers for a few specific divisors.
+ // Details and proofs can be found in:
+ // - Hacker's Delight, Henry S. Warren, Jr.
+ // - The PowerPC Compiler Writer's Guide
+ // and probably many others.
+ //
+ // We handle
+ // <divisor with magic numbers> * <power of 2>
+ // but not
+ // <divisor with magic numbers> * <other divisor with magic numbers>
+ int32_t power_of_2_factor =
+ CompilerIntrinsics::CountTrailingZeros(divisor_abs);
+ DivMagicNumbers magic_numbers =
+ DivMagicNumberFor(divisor_abs >> power_of_2_factor);
+ if (magic_numbers.M != InvalidDivMagicNumber.M) return true;
+
+ return false;
+}
+
+
+HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
+ // Only optimize when we have magic numbers for the divisor.
+ // The standard integer division routine is usually slower than transitionning
+ // to FPU.
+ if (divisor->IsConstant() &&
+ HConstant::cast(divisor)->HasInteger32Value()) {
+ HConstant* constant_val = HConstant::cast(divisor);
+ return constant_val->CopyToRepresentation(Representation::Integer32(),
+ divisor->block()->zone());
+ }
return NULL;
}
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+ HValue* right = instr->right();
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegisterOrConstant(right);
+ LOperand* remainder = TempRegister();
+ ASSERT(right->IsConstant() &&
+ HConstant::cast(right)->HasInteger32Value());
+ return AssignEnvironment(DefineAsRegister(
+ new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
+}
+
+
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
@@ -2451,8 +2510,9 @@
undefined,
instr->inlining_kind(),
instr->undefined_receiver());
- if (instr->arguments_var() != NULL) {
- inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
+ // Only replay binding of arguments object if it wasn't removed from graph.
+ if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
+ inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 50feee0..32db0dd 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -137,6 +137,7 @@
V(MathCos) \
V(MathExp) \
V(MathFloor) \
+ V(MathFloorOfDiv) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
@@ -623,6 +624,25 @@
};
+class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> {
+ public:
+ LMathFloorOfDiv(LOperand* left,
+ LOperand* right,
+ LOperand* temp = NULL) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ temps_[0] = temp;
+ }
+
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div")
+ DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
class LMulI: public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
@@ -2642,6 +2662,9 @@
LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+ static bool HasMagicNumberForDivisor(int32_t divisor);
+ static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
+
LInstruction* DoMathFloor(HUnaryMathOperation* instr);
LInstruction* DoMathRound(HUnaryMathOperation* instr);
LInstruction* DoMathAbs(HUnaryMathOperation* instr);
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 15436e7..d41ddd2 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -3909,6 +3909,9 @@
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
+ Address function_address,
+ ExternalReference thunk_ref,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_fp) {
@@ -3947,11 +3950,30 @@
addiu(a0, fp, ExitFrameConstants::kStackSpaceOffset);
}
+ Label profiler_disabled;
+ Label end_profiler_check;
+ bool* is_profiling_flag =
+ isolate()->cpu_profiler()->is_profiling_address();
+ STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+ li(t9, reinterpret_cast<int32_t>(is_profiling_flag));
+ lb(t9, MemOperand(t9, 0));
+ beq(t9, zero_reg, &profiler_disabled);
+
+ // Third parameter is the address of the actual getter function.
+ li(thunk_last_arg, reinterpret_cast<int32_t>(function_address));
+ li(t9, Operand(thunk_ref));
+ jmp(&end_profiler_check);
+
+ bind(&profiler_disabled);
+ li(t9, Operand(function));
+
+ bind(&end_profiler_check);
+
// Native call returns to the DirectCEntry stub which redirects to the
// return address pushed on stack (could have moved after GC).
// DirectCEntry stub itself is generated early and never moves.
DirectCEntryStub stub;
- stub.GenerateCall(this, function);
+ stub.GenerateCall(this, t9);
if (FLAG_log_timer_events) {
FrameScope frame(this, StackFrame::MANUAL);
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 5e6bfba..c983b8b 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -1235,6 +1235,9 @@
// - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function,
+ Address function_address,
+ ExternalReference thunk_ref,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_fp);
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index d8a39ab..8771bd2 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -1394,6 +1394,9 @@
// Here, we pass the first argument in a0, because this function
// does not return a struct.
typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)(
+ int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1);
// This signature supports direct call to accessor getter callback.
// See comment at SimulatorRuntimeDirectApiCall.
@@ -1402,6 +1405,10 @@
// See comment at SimulatorRuntimeDirectApiCallNew.
typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0,
int32_t arg1);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)(
+ int32_t arg0, int32_t arg1, int32_t arg2);
+typedef void (*SimulatorRuntimeProfilingGetterCallNew)(
+ int32_t arg0, int32_t arg1, int32_t arg2);
// Software interrupt instructions are used by the simulator to call into the
// C-based V8 runtime. They are also used for debugging with simulator.
@@ -1571,6 +1578,30 @@
target(arg0);
}
} else if (
+ redirection->type() == ExternalReference::PROFILING_API_CALL ||
+ redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) {
+ if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
+ // See comment at type definition of SimulatorRuntimeDirectApiCall
+ // for explanation of register usage.
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Call to host function at %p args %08x %08x\n",
+ reinterpret_cast<void*>(external), arg1, arg2);
+ }
+ SimulatorRuntimeProfilingApiCall target =
+ reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+ v8::Handle<v8::Value> result = target(arg1, arg2);
+ *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
+ set_register(v0, arg0);
+ } else {
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Call to host function at %p args %08x %08x\n",
+ reinterpret_cast<void*>(external), arg0, arg1);
+ }
+ SimulatorRuntimeProfilingApiCallNew target =
+ reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external);
+ target(arg0, arg1);
+ }
+ } else if (
redirection->type() == ExternalReference::DIRECT_GETTER_CALL ||
redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) {
if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
@@ -1594,6 +1625,30 @@
reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external);
target(arg0, arg1);
}
+ } else if (
+ redirection->type() == ExternalReference::PROFILING_GETTER_CALL ||
+ redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) {
+ if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
+ // See comment at type definition of SimulatorRuntimeProfilingGetterCall
+ // for explanation of register usage.
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Call to host function at %p args %08x %08x %08x\n",
+ reinterpret_cast<void*>(external), arg1, arg2, arg3);
+ }
+ SimulatorRuntimeProfilingGetterCall target =
+ reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
+ v8::Handle<v8::Value> result = target(arg1, arg2, arg3);
+ *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
+ set_register(v0, arg0);
+ } else {
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Call to host function at %p args %08x %08x %08x\n",
+ reinterpret_cast<void*>(external), arg0, arg1, arg2);
+ }
+ SimulatorRuntimeProfilingGetterCallNew target =
+ reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>(external);
+ target(arg0, arg1, arg2);
+ }
} else {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 6e42242..51df452 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -503,7 +503,12 @@
Register storage_reg = name_reg;
- if (FLAG_track_fields && representation.IsSmi()) {
+ if (details.type() == CONSTANT_FUNCTION) {
+ Handle<HeapObject> constant(
+ HeapObject::cast(descriptors->GetValue(descriptor)));
+ __ LoadHeapObject(scratch1, constant);
+ __ Branch(miss_restore_name, ne, value_reg, Operand(scratch1));
+ } else if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
@@ -532,7 +537,8 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (object->map()->unused_property_fields() == 0) {
+ if (details.type() == FIELD &&
+ object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ push(receiver_reg);
@@ -560,6 +566,13 @@
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ if (details.type() == CONSTANT_FUNCTION) {
+ ASSERT(value_reg.is(a0));
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a0);
+ return;
+ }
+
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
@@ -932,6 +945,7 @@
!CallbackTable::ReturnsVoid(masm->isolate(), function_address);
Register first_arg = returns_handle ? a1 : a0;
+ Register second_arg = returns_handle ? a2 : a1;
// first_arg = v8::Arguments&
// Arguments is built at sp + 1 (sp is a reserved spot for ra).
@@ -958,8 +972,23 @@
ExternalReference(&fun,
type,
masm->isolate());
+
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeInvocationCallback)
+ : FUNCTION_ADDR(&InvokeFunctionCallback);
+ ExternalReference::Type thunk_type =
+ returns_handle ?
+ ExternalReference::PROFILING_API_CALL :
+ ExternalReference::PROFILING_API_CALL_NEW;
+ ApiFunction thunk_fun(thunk_address);
+ ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+ masm->isolate());
+
AllowExternalCallThatCantCauseGC scope(masm);
__ CallApiFunctionAndReturn(ref,
+ function_address,
+ thunk_ref,
+ second_arg,
kStackUnwindSpace,
returns_handle,
kFastApiCallArguments + 1);
@@ -1452,6 +1481,7 @@
Register first_arg = returns_handle ? a1 : a0;
Register second_arg = returns_handle ? a2 : a1;
+ Register third_arg = returns_handle ? a3 : a2;
__ mov(a2, scratch2()); // Saved in case scratch2 == a1.
__ mov(first_arg, sp); // (first argument - see note below) = Handle<Name>
@@ -1472,14 +1502,28 @@
__ Addu(second_arg, sp, kPointerSize);
const int kStackUnwindSpace = kFastApiCallArguments + 1;
+
ApiFunction fun(getter_address);
ExternalReference::Type type =
returns_handle ?
ExternalReference::DIRECT_GETTER_CALL :
ExternalReference::DIRECT_GETTER_CALL_NEW;
-
ExternalReference ref = ExternalReference(&fun, type, isolate());
+
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeAccessorGetter)
+ : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+ ExternalReference::Type thunk_type =
+ returns_handle ?
+ ExternalReference::PROFILING_GETTER_CALL :
+ ExternalReference::PROFILING_GETTER_CALL_NEW;
+ ApiFunction thunk_fun(thunk_address);
+ ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+ isolate());
__ CallApiFunctionAndReturn(ref,
+ getter_address,
+ thunk_ref,
+ third_arg,
kStackUnwindSpace,
returns_handle,
5);
@@ -2707,7 +2751,7 @@
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
// ----------- S t a t e -------------
@@ -2883,7 +2927,7 @@
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name) {
Label miss;
@@ -3023,7 +3067,7 @@
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<GlobalObject> global,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 3b561ee..ca42383 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -167,7 +167,7 @@
Cell::cast(this)->CellVerify();
break;
case PROPERTY_CELL_TYPE:
- JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellVerify();
+ PropertyCell::cast(this)->PropertyCellVerify();
break;
case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify();
@@ -624,8 +624,8 @@
}
-void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() {
- CHECK(IsJSGlobalPropertyCell());
+void PropertyCell::PropertyCellVerify() {
+ CHECK(IsPropertyCell());
VerifyObjectField(kValueOffset);
VerifyObjectField(kTypeOffset);
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 24af123..5d4d9d3 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -669,7 +669,7 @@
TYPE_CHECKER(Code, CODE_TYPE)
TYPE_CHECKER(Oddball, ODDBALL_TYPE)
TYPE_CHECKER(Cell, CELL_TYPE)
-TYPE_CHECKER(JSGlobalPropertyCell, PROPERTY_CELL_TYPE)
+TYPE_CHECKER(PropertyCell, PROPERTY_CELL_TYPE)
TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE)
TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
@@ -1629,17 +1629,17 @@
void Cell::set_value(Object* val, WriteBarrierMode ignored) {
// The write barrier is not used for global property cells.
- ASSERT(!val->IsJSGlobalPropertyCell() && !val->IsCell());
+ ASSERT(!val->IsPropertyCell() && !val->IsCell());
WRITE_FIELD(this, kValueOffset, val);
}
-Object* JSGlobalPropertyCell::type_raw() {
+Object* PropertyCell::type_raw() {
return READ_FIELD(this, kTypeOffset);
}
-void JSGlobalPropertyCell::set_type_raw(Object* val, WriteBarrierMode ignored) {
+void PropertyCell::set_type_raw(Object* val, WriteBarrierMode ignored) {
WRITE_FIELD(this, kTypeOffset, val);
}
@@ -2091,30 +2091,6 @@
}
-void FixedArray::set_unchecked(int index, Smi* value) {
- ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
- int offset = kHeaderSize + index * kPointerSize;
- WRITE_FIELD(this, offset, value);
-}
-
-
-void FixedArray::set_unchecked(Heap* heap,
- int index,
- Object* value,
- WriteBarrierMode mode) {
- int offset = kHeaderSize + index * kPointerSize;
- WRITE_FIELD(this, offset, value);
- CONDITIONAL_WRITE_BARRIER(heap, this, offset, value, mode);
-}
-
-
-void FixedArray::set_null_unchecked(Heap* heap, int index) {
- ASSERT(index >= 0 && index < this->length());
- ASSERT(!heap->InNewSpace(heap->null_value()));
- WRITE_FIELD(this, kHeaderSize + index * kPointerSize, heap->null_value());
-}
-
-
double* FixedDoubleArray::data_start() {
return reinterpret_cast<double*>(FIELD_ADDR(this, kHeaderSize));
}
@@ -2564,7 +2540,7 @@
CAST_ACCESSOR(HeapNumber)
CAST_ACCESSOR(Oddball)
CAST_ACCESSOR(Cell)
-CAST_ACCESSOR(JSGlobalPropertyCell)
+CAST_ACCESSOR(PropertyCell)
CAST_ACCESSOR(SharedFunctionInfo)
CAST_ACCESSOR(Map)
CAST_ACCESSOR(JSFunction)
@@ -3577,11 +3553,6 @@
}
-JSFunction* Map::unchecked_constructor() {
- return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
-}
-
-
Code::Flags Code::flags() {
return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset));
}
@@ -3653,6 +3624,9 @@
details.representation().IsHeapObject()) {
return true;
}
+ if (FLAG_track_fields && details.type() == CONSTANT_FUNCTION) {
+ return true;
+ }
}
return false;
}
@@ -4744,11 +4718,6 @@
}
-Code* SharedFunctionInfo::unchecked_code() {
- return reinterpret_cast<Code*>(READ_FIELD(this, kCodeOffset));
-}
-
-
void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) {
WRITE_FIELD(this, kCodeOffset, value);
CONDITIONAL_WRITE_BARRIER(value->GetHeap(), this, kCodeOffset, value, mode);
@@ -5285,12 +5254,6 @@
}
-FixedArray* Code::unchecked_deoptimization_data() {
- return reinterpret_cast<FixedArray*>(
- READ_FIELD(this, kDeoptimizationDataOffset));
-}
-
-
ByteArray* Code::unchecked_relocation_info() {
return reinterpret_cast<ByteArray*>(READ_FIELD(this, kRelocationInfoOffset));
}
@@ -5366,12 +5329,6 @@
}
-JSRegExp::Type JSRegExp::TypeTagUnchecked() {
- Smi* smi = Smi::cast(DataAtUnchecked(kTagIndex));
- return static_cast<JSRegExp::Type>(smi->value());
-}
-
-
int JSRegExp::CaptureCount() {
switch (TypeTag()) {
case ATOM:
@@ -5407,13 +5364,6 @@
}
-Object* JSRegExp::DataAtUnchecked(int index) {
- FixedArray* fa = reinterpret_cast<FixedArray*>(data());
- int offset = FixedArray::kHeaderSize + index * kPointerSize;
- return READ_FIELD(fa, offset);
-}
-
-
void JSRegExp::SetDataAt(int index, Object* value) {
ASSERT(TypeTag() != NOT_COMPILED);
ASSERT(index >= kDataIndex); // Only implementation data can be set this way.
@@ -5421,18 +5371,6 @@
}
-void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) {
- ASSERT(index >= kDataIndex); // Only implementation data can be set this way.
- FixedArray* fa = reinterpret_cast<FixedArray*>(data());
- if (value->IsSmi()) {
- fa->set_unchecked(index, Smi::cast(value));
- } else {
- // We only do this during GC, so we don't need to notify the write barrier.
- fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER);
- }
-}
-
-
ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
#if DEBUG
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 33aa404..a57088b 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -186,7 +186,7 @@
Cell::cast(this)->CellPrint(out);
break;
case PROPERTY_CELL_TYPE:
- JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out);
+ PropertyCell::cast(this)->PropertyCellPrint(out);
break;
case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
@@ -926,8 +926,8 @@
}
-void JSGlobalPropertyCell::JSGlobalPropertyCellPrint(FILE* out) {
- HeapObject::PrintHeader(out, "JSGlobalPropertyCell");
+void PropertyCell::PropertyCellPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "PropertyCell");
}
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index c138fdd..9dc245c 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -203,7 +203,7 @@
table_.Register(kVisitPropertyCell,
&FixedBodyVisitor<StaticVisitor,
- JSGlobalPropertyCell::BodyDescriptor,
+ PropertyCell::BodyDescriptor,
void>::Visit);
table_.template RegisterSpecializations<DataObjectVisitor,
diff --git a/src/objects.cc b/src/objects.cc
index 54d25a7..e9b7ec2 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -629,9 +629,9 @@
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
if (IsGlobalObject()) {
- value = JSGlobalPropertyCell::cast(value)->value();
+ value = PropertyCell::cast(value)->value();
}
- ASSERT(!value->IsJSGlobalPropertyCell() && !value->IsCell());
+ ASSERT(!value->IsPropertyCell() && !value->IsCell());
return value;
}
@@ -639,7 +639,7 @@
Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
ASSERT(!HasFastProperties());
if (IsGlobalObject()) {
- JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(
+ PropertyCell* cell = PropertyCell::cast(
property_dictionary()->ValueAt(result->GetDictionaryEntry()));
cell->set_value(value);
} else {
@@ -669,7 +669,7 @@
if (IsGlobalObject()) {
Heap* heap = name->GetHeap();
MaybeObject* maybe_store_value =
- heap->AllocateJSGlobalPropertyCell(value);
+ heap->AllocatePropertyCell(value);
if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
}
Object* dict;
@@ -696,8 +696,8 @@
details.attributes(), details.type(), enumeration_index);
if (IsGlobalObject()) {
- JSGlobalPropertyCell* cell =
- JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
+ PropertyCell* cell =
+ PropertyCell::cast(property_dictionary()->ValueAt(entry));
cell->set_value(value);
// Please note we have to update the property details.
property_dictionary()->DetailsAtPut(entry, details);
@@ -729,8 +729,7 @@
ASSERT(new_map->is_dictionary_map());
set_map(new_map);
}
- JSGlobalPropertyCell* cell =
- JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
+ PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
cell->set_value(cell->GetHeap()->the_hole_value());
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
@@ -1384,7 +1383,7 @@
global_object ? "Global Object: " : "",
vowel ? "n" : "");
accumulator->Put(str);
- accumulator->Add(" with %smap 0x%p",
+ accumulator->Add(" with %smap %p",
map_of_this->is_deprecated() ? "deprecated " : "",
map_of_this);
printed = true;
@@ -1572,7 +1571,7 @@
break;
case PROPERTY_CELL_TYPE:
accumulator->Add("PropertyCell for ");
- JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
+ PropertyCell::cast(this)->value()->ShortPrint(accumulator);
break;
default:
accumulator->Add("<Other heap object (%d)>", map()->instance_type());
@@ -1668,7 +1667,7 @@
Cell::BodyDescriptor::IterateBody(this, v);
break;
case PROPERTY_CELL_TYPE:
- JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
+ PropertyCell::BodyDescriptor::IterateBody(this, v);
break;
case SYMBOL_TYPE:
Symbol::BodyDescriptor::IterateBody(this, v);
@@ -1937,7 +1936,7 @@
int entry = dict->FindEntry(name);
if (entry != NameDictionary::kNotFound) {
store_value = dict->ValueAt(entry);
- JSGlobalPropertyCell::cast(store_value)->set_value(value);
+ PropertyCell::cast(store_value)->set_value(value);
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = dict->NextEnumerationIndex();
@@ -1948,10 +1947,10 @@
}
Heap* heap = GetHeap();
{ MaybeObject* maybe_store_value =
- heap->AllocateJSGlobalPropertyCell(value);
+ heap->AllocatePropertyCell(value);
if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
}
- JSGlobalPropertyCell::cast(store_value)->set_value(value);
+ PropertyCell::cast(store_value)->set_value(value);
}
PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
Object* result;
@@ -3273,7 +3272,7 @@
result->NotFound();
return;
}
- value = JSGlobalPropertyCell::cast(value)->value();
+ value = PropertyCell::cast(value)->value();
}
// Make sure to disallow caching for uninitialized constants
// found in the dictionary-mode objects.
@@ -9199,7 +9198,10 @@
void JSFunction::MarkForParallelRecompilation() {
ASSERT(is_compiled() && !IsOptimized());
ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
- ASSERT(FLAG_parallel_recompilation);
+ if (!FLAG_parallel_recompilation) {
+ JSFunction::MarkForLazyRecompilation();
+ return;
+ }
if (FLAG_trace_parallel_recompilation) {
PrintF(" ** Marking ");
PrintName();
@@ -10556,11 +10558,8 @@
}
case Translation::ARGUMENTS_OBJECT: {
- bool args_known = iterator.Next();
- int args_index = iterator.Next();
int args_length = iterator.Next();
- PrintF(out, "{index=%d, length=%d, known=%d}",
- args_index, args_length, args_known);
+ PrintF(out, "{length=%d}", args_length);
break;
}
}
@@ -12061,7 +12060,7 @@
StrictModeFlag strict_mode,
SetPropertyMode set_mode) {
if (object->HasExternalArrayElements()) {
- if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
+ if (!value->IsNumber() && !value->IsUndefined()) {
bool has_exception;
Handle<Object> number = Execution::ToNumber(value, &has_exception);
if (has_exception) return Handle<Object>();
@@ -14262,20 +14261,20 @@
}
-JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
+PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
- return JSGlobalPropertyCell::cast(value);
+ return PropertyCell::cast(value);
}
-Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
+Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
Handle<GlobalObject> global,
Handle<Name> name) {
Isolate* isolate = global->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
global->EnsurePropertyCell(*name),
- JSGlobalPropertyCell);
+ PropertyCell);
}
@@ -14286,7 +14285,7 @@
Heap* heap = GetHeap();
Object* cell;
{ MaybeObject* maybe_cell =
- heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
+ heap->AllocatePropertyCell(heap->the_hole_value());
if (!maybe_cell->ToObject(&cell)) return maybe_cell;
}
PropertyDetails details(NONE, NORMAL, 0);
@@ -14300,7 +14299,7 @@
return cell;
} else {
Object* value = property_dictionary()->ValueAt(entry);
- ASSERT(value->IsJSGlobalPropertyCell());
+ ASSERT(value->IsPropertyCell());
return value;
}
}
@@ -15083,8 +15082,8 @@
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (Dictionary<Shape, Key>::IsKey(k)) {
Object* e = ValueAt(i);
- if (e->IsJSGlobalPropertyCell()) {
- e = JSGlobalPropertyCell::cast(e)->value();
+ if (e->IsPropertyCell()) {
+ e = PropertyCell::cast(e)->value();
}
if (e == value) return k;
}
@@ -15814,12 +15813,12 @@
}
-Type* JSGlobalPropertyCell::type() {
+Type* PropertyCell::type() {
return static_cast<Type*>(type_raw());
}
-void JSGlobalPropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
+void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
set_type_raw(type, ignored);
}
diff --git a/src/objects.h b/src/objects.h
index 7771eb4..1d02ed7 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -120,7 +120,7 @@
// - Symbol
// - HeapNumber
// - Cell
-// - JSGlobalPropertyCell
+// - PropertyCell
// - Code
// - Map
// - Oddball
@@ -1017,7 +1017,7 @@
V(UndetectableObject) \
V(AccessCheckNeeded) \
V(Cell) \
- V(JSGlobalPropertyCell) \
+ V(PropertyCell) \
V(ObjectHashTable) \
@@ -2571,7 +2571,7 @@
inline void set(int index, Object* value);
inline bool is_the_hole(int index);
- // Setter that doesn't need write barrier).
+ // Setter that doesn't need write barrier.
inline void set(int index, Smi* value);
// Setter with explicit barrier mode.
inline void set(int index, Object* value, WriteBarrierMode mode);
@@ -2585,12 +2585,6 @@
inline void set_null(Heap* heap, int index);
inline void set_the_hole(int index);
- // Setters with less debug checks for the GC to use.
- inline void set_unchecked(int index, Smi* value);
- inline void set_null_unchecked(Heap* heap, int index);
- inline void set_unchecked(Heap* heap, int index, Object* value,
- WriteBarrierMode mode);
-
inline Object** GetFirstElementAddress();
inline bool ContainsOnlySmisOrHoles();
@@ -4385,7 +4379,7 @@
// Forward declaration.
class Cell;
-class JSGlobalPropertyCell;
+class PropertyCell;
// TypeFeedbackCells is a fixed array used to hold the association between
// cache cells and AST ids for code generated by the full compiler.
@@ -4553,7 +4547,6 @@
// Unchecked accessors to be used during GC.
inline ByteArray* unchecked_relocation_info();
- inline FixedArray* unchecked_deoptimization_data();
inline int relocation_size();
@@ -5320,8 +5313,6 @@
// [constructor]: points back to the function responsible for this map.
DECL_ACCESSORS(constructor, Object)
- inline JSFunction* unchecked_constructor();
-
// [instance descriptors]: describes the object.
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
inline void InitializeDescriptors(DescriptorArray* descriptors);
@@ -5373,8 +5364,7 @@
inline void SetNumberOfProtoTransitions(int value) {
FixedArray* cache = GetPrototypeTransitions();
ASSERT(cache->length() != 0);
- cache->set_unchecked(kProtoTransitionNumberOfEntriesOffset,
- Smi::FromInt(value));
+ cache->set(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value));
}
// Lookup in the map's instance descriptors and fill out the result
@@ -5940,8 +5930,6 @@
// [construct stub]: Code stub for constructing instances of this function.
DECL_ACCESSORS(construct_stub, Code)
- inline Code* unchecked_code();
-
// Returns if this function has been compiled to native code yet.
inline bool is_compiled();
@@ -6821,7 +6809,7 @@
DECL_ACCESSORS(global_receiver, JSObject)
// Retrieve the property cell used to store a property.
- JSGlobalPropertyCell* GetPropertyCell(LookupResult* result);
+ PropertyCell* GetPropertyCell(LookupResult* result);
// This is like GetProperty, but is used when you know the lookup won't fail
// by throwing an exception. This is for the debug and builtins global
@@ -6833,7 +6821,7 @@
}
// Ensure that the global object has a cell for the given property name.
- static Handle<JSGlobalPropertyCell> EnsurePropertyCell(
+ static Handle<PropertyCell> EnsurePropertyCell(
Handle<GlobalObject> global,
Handle<Name> name);
// TODO(kmillikin): This function can be eliminated once the stub cache is
@@ -7132,11 +7120,6 @@
// Set implementation data after the object has been prepared.
inline void SetDataAt(int index, Object* value);
- // Used during GC when flushing code or setting age.
- inline Object* DataAtUnchecked(int index);
- inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
- inline Type TypeTagUnchecked();
-
static int code_index(bool is_ascii) {
if (is_ascii) {
return kIrregexpASCIICodeIndex;
@@ -8570,7 +8553,7 @@
static inline Cell* FromValueAddress(Address value) {
Object* result = FromAddress(value - kValueOffset);
- ASSERT(result->IsCell() || result->IsJSGlobalPropertyCell());
+ ASSERT(result->IsCell() || result->IsPropertyCell());
return static_cast<Cell*>(result);
}
@@ -8595,21 +8578,21 @@
};
-class JSGlobalPropertyCell: public Cell {
+class PropertyCell: public Cell {
public:
Type* type();
void set_type(Type* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Casting.
- static inline JSGlobalPropertyCell* cast(Object* obj);
+ static inline PropertyCell* cast(Object* obj);
inline Address TypeAddress() {
return address() + kTypeOffset;
}
// Dispatched behavior.
- DECLARE_PRINTER(JSGlobalPropertyCell)
- DECLARE_VERIFIER(JSGlobalPropertyCell)
+ DECLARE_PRINTER(PropertyCell)
+ DECLARE_VERIFIER(PropertyCell)
// Layout description.
static const int kTypeOffset = kValueOffset + kPointerSize;
@@ -8618,11 +8601,11 @@
typedef FixedBodyDescriptor<
kValueOffset,
kTypeOffset + kPointerSize,
- JSGlobalPropertyCell::kSize> BodyDescriptor;
+ PropertyCell::kSize> BodyDescriptor;
private:
DECL_ACCESSORS(type_raw, Object)
- DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalPropertyCell);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
};
diff --git a/src/property-details.h b/src/property-details.h
index 669b05d..b0d10e1 100644
--- a/src/property-details.h
+++ b/src/property-details.h
@@ -110,6 +110,10 @@
(!IsDouble() && !other.IsDouble());
}
+ bool IsCompatibleForStore(const Representation& other) const {
+ return Equals(other);
+ }
+
bool is_more_general_than(const Representation& other) const {
ASSERT(kind_ != kExternal);
ASSERT(other.kind_ != kExternal);
diff --git a/src/property.h b/src/property.h
index f853fc8..f36bc7a 100644
--- a/src/property.h
+++ b/src/property.h
@@ -351,7 +351,7 @@
Object* value;
value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
if (holder()->IsGlobalObject()) {
- value = JSGlobalPropertyCell::cast(value)->value();
+ value = PropertyCell::cast(value)->value();
}
return value;
}
@@ -392,6 +392,11 @@
return IsTransition() && GetTransitionDetails(map).type() == FIELD;
}
+ bool IsTransitionToConstantFunction(Map* map) {
+ return IsTransition() &&
+ GetTransitionDetails(map).type() == CONSTANT_FUNCTION;
+ }
+
Map* GetTransitionMap() {
ASSERT(IsTransition());
return Map::cast(GetValue());
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index c4b79b1..9b7dd34 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -80,11 +80,17 @@
STATIC_ASSERT(kProfilerTicksBeforeReenablingOptimization < 256);
STATIC_ASSERT(kTicksWhenNotEnoughTypeInfo < 256);
+// Maximum size in bytes of generate code for a function to allow OSR.
+static const int kOSRCodeSizeAllowanceBase =
+ 100 * FullCodeGenerator::kCodeSizeMultiplier;
+
+static const int kOSRCodeSizeAllowancePerTick =
+ 3 * FullCodeGenerator::kCodeSizeMultiplier;
// Maximum size in bytes of generated code for a function to be optimized
// the very first time it is seen on the stack.
static const int kMaxSizeEarlyOpt =
- 5 * FullCodeGenerator::kBackEdgeDistanceUnit;
+ 5 * FullCodeGenerator::kCodeSizeMultiplier;
RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
@@ -100,14 +106,13 @@
}
-static void GetICCounts(JSFunction* function,
+static void GetICCounts(Code* shared_code,
int* ic_with_type_info_count,
int* ic_total_count,
int* percentage) {
*ic_total_count = 0;
*ic_with_type_info_count = 0;
- Object* raw_info =
- function->shared()->code()->type_feedback_info();
+ Object* raw_info = shared_code->type_feedback_info();
if (raw_info->IsTypeFeedbackInfo()) {
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(raw_info);
*ic_with_type_info_count = info->ic_with_type_info_count();
@@ -128,7 +133,7 @@
PrintF(" for recompilation, reason: %s", reason);
if (FLAG_type_info_threshold > 0) {
int typeinfo, total, percentage;
- GetICCounts(function, &typeinfo, &total, &percentage);
+ GetICCounts(function->shared()->code(), &typeinfo, &total, &percentage);
PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total, percentage);
}
PrintF("]\n");
@@ -274,12 +279,20 @@
(function->IsMarkedForLazyRecompilation() ||
function->IsMarkedForParallelRecompilation() ||
function->IsOptimized())) {
- int nesting = shared_code->allow_osr_at_loop_nesting_level();
- if (nesting < Code::kMaxLoopNestingMarker) {
- int new_nesting = nesting + 1;
- shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
- AttemptOnStackReplacement(function);
+ int ticks = shared_code->profiler_ticks();
+ int allowance = kOSRCodeSizeAllowanceBase +
+ ticks * kOSRCodeSizeAllowancePerTick;
+ if (shared_code->CodeSize() > allowance) {
+ if (ticks < 255) shared_code->set_profiler_ticks(ticks + 1);
+ } else {
+ int nesting = shared_code->allow_osr_at_loop_nesting_level();
+ if (nesting < Code::kMaxLoopNestingMarker) {
+ int new_nesting = nesting + 1;
+ shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
+ AttemptOnStackReplacement(function);
+ }
}
+ continue;
}
// Only record top-level code on top of the execution stack and
@@ -313,7 +326,7 @@
if (ticks >= kProfilerTicksBeforeOptimization) {
int typeinfo, total, percentage;
- GetICCounts(function, &typeinfo, &total, &percentage);
+ GetICCounts(shared_code, &typeinfo, &total, &percentage);
if (percentage >= FLAG_type_info_threshold) {
// If this particular function hasn't had any ICs patched for enough
// ticks, optimize it now.
diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h
index 1bf9aa8..46da381 100644
--- a/src/runtime-profiler.h
+++ b/src/runtime-profiler.h
@@ -75,6 +75,8 @@
void AddSample(JSFunction* function, int weight);
+ bool CodeSizeOKForOSR(Code* shared_code);
+
Isolate* isolate_;
int sampler_threshold_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 01165c8..0c744ca 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4513,7 +4513,7 @@
(dictionary->DetailsAt(entry).type() == NORMAL)) {
Object* value = dictionary->ValueAt(entry);
if (!receiver->IsGlobalObject()) return value;
- value = JSGlobalPropertyCell::cast(value)->value();
+ value = PropertyCell::cast(value)->value();
if (!value->IsTheHole()) return value;
// If value is the hole do the general lookup.
}
@@ -4753,25 +4753,40 @@
}
js_object->ValidateElements();
- Handle<Object> result = JSObject::SetElement(
- js_object, index, value, attr, strict_mode, set_mode);
+ if (js_object->HasExternalArrayElements()) {
+ if (!value->IsNumber() && !value->IsUndefined()) {
+ bool has_exception;
+ Handle<Object> number = Execution::ToNumber(value, &has_exception);
+ if (has_exception) return Failure::Exception();
+ value = number;
+ }
+ }
+ MaybeObject* result = js_object->SetElement(
+ index, *value, attr, strict_mode, true, set_mode);
js_object->ValidateElements();
- if (result.is_null()) return Failure::Exception();
+ if (result->IsFailure()) return result;
return *value;
}
if (key->IsName()) {
- Handle<Object> result;
+ MaybeObject* result;
Handle<Name> name = Handle<Name>::cast(key);
if (name->AsArrayIndex(&index)) {
- result = JSObject::SetElement(
- js_object, index, value, attr, strict_mode, set_mode);
+ if (js_object->HasExternalArrayElements()) {
+ if (!value->IsNumber() && !value->IsUndefined()) {
+ bool has_exception;
+ Handle<Object> number = Execution::ToNumber(value, &has_exception);
+ if (has_exception) return Failure::Exception();
+ value = number;
+ }
+ }
+ result = js_object->SetElement(
+ index, *value, attr, strict_mode, true, set_mode);
} else {
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
- result = JSReceiver::SetProperty(
- js_object, name, value, attr, strict_mode);
+ result = js_object->SetProperty(*name, *value, attr, strict_mode);
}
- if (result.is_null()) return Failure::Exception();
+ if (result->IsFailure()) return result;
return *value;
}
@@ -8070,6 +8085,13 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsParallelRecompilationSupported) {
+ HandleScope scope(isolate);
+ return FLAG_parallel_recompilation
+ ? isolate->heap()->true_value() : isolate->heap()->false_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
diff --git a/src/runtime.h b/src/runtime.h
index c52bbe7..d2daddf 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -95,6 +95,7 @@
F(DeoptimizeFunction, 1, 1) \
F(ClearFunctionTypeFeedback, 1, 1) \
F(RunningInSimulator, 0, 1) \
+ F(IsParallelRecompilationSupported, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(CompleteOptimization, 1, 1) \
F(GetOptimizationStatus, 1, 1) \
diff --git a/src/sampler.cc b/src/sampler.cc
index efac288..96b20f0 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -496,9 +496,7 @@
void SampleContext(Sampler* sampler) {
if (!SignalHandler::Installed()) return;
pthread_t tid = sampler->platform_data()->vm_tid();
- int result = pthread_kill(tid, SIGPROF);
- USE(result);
- ASSERT(result == 0);
+ pthread_kill(tid, SIGPROF);
}
#elif defined(__MACH__)
diff --git a/src/spaces.cc b/src/spaces.cc
index 8e953e2..825d2a6 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1045,7 +1045,7 @@
size = 16 * kPointerSize * KB;
break;
case PROPERTY_CELL_SPACE:
- size = 16 * kPointerSize * KB;
+ size = 8 * kPointerSize * KB;
break;
case CODE_SPACE:
if (heap()->isolate()->code_range()->exists()) {
@@ -2118,13 +2118,13 @@
while (node != NULL &&
Page::FromAddress(node->address())->IsEvacuationCandidate()) {
- available_ -= node->Size();
+ available_ -= reinterpret_cast<FreeSpace*>(node)->Size();
node = node->next();
}
if (node != NULL) {
set_top(node->next());
- *node_size = node->Size();
+ *node_size = reinterpret_cast<FreeSpace*>(node)->Size();
available_ -= *node_size;
} else {
set_top(NULL);
@@ -2138,6 +2138,18 @@
}
+FreeListNode* FreeListCategory::PickNodeFromList(int size_in_bytes,
+ int *node_size) {
+ FreeListNode* node = PickNodeFromList(node_size);
+ if (node != NULL && *node_size < size_in_bytes) {
+ Free(node, *node_size);
+ *node_size = 0;
+ return NULL;
+ }
+ return node;
+}
+
+
void FreeListCategory::Free(FreeListNode* node, int size_in_bytes) {
node->set_next(top_);
top_ = node;
@@ -2227,8 +2239,10 @@
if (size_in_bytes <= kSmallAllocationMax) {
node = small_list_.PickNodeFromList(node_size);
if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
page = Page::FromAddress(node->address());
page->add_available_in_small_free_list(-(*node_size));
+ ASSERT(IsVeryLong() || available() == SumFreeLists());
return node;
}
}
@@ -2236,8 +2250,10 @@
if (size_in_bytes <= kMediumAllocationMax) {
node = medium_list_.PickNodeFromList(node_size);
if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
page = Page::FromAddress(node->address());
page->add_available_in_medium_free_list(-(*node_size));
+ ASSERT(IsVeryLong() || available() == SumFreeLists());
return node;
}
}
@@ -2245,8 +2261,10 @@
if (size_in_bytes <= kLargeAllocationMax) {
node = large_list_.PickNodeFromList(node_size);
if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
page = Page::FromAddress(node->address());
page->add_available_in_large_free_list(-(*node_size));
+ ASSERT(IsVeryLong() || available() == SumFreeLists());
return node;
}
}
@@ -2289,10 +2307,37 @@
if (huge_list_.top() == NULL) {
huge_list_.set_end(NULL);
}
-
huge_list_.set_available(huge_list_available);
- ASSERT(IsVeryLong() || available() == SumFreeLists());
+ if (node != NULL) {
+ ASSERT(IsVeryLong() || available() == SumFreeLists());
+ return node;
+ }
+
+ if (size_in_bytes <= kSmallListMax) {
+ node = small_list_.PickNodeFromList(size_in_bytes, node_size);
+ if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
+ page = Page::FromAddress(node->address());
+ page->add_available_in_small_free_list(-(*node_size));
+ }
+ } else if (size_in_bytes <= kMediumListMax) {
+ node = medium_list_.PickNodeFromList(size_in_bytes, node_size);
+ if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
+ page = Page::FromAddress(node->address());
+ page->add_available_in_medium_free_list(-(*node_size));
+ }
+ } else if (size_in_bytes <= kLargeListMax) {
+ node = large_list_.PickNodeFromList(size_in_bytes, node_size);
+ if (node != NULL) {
+ ASSERT(size_in_bytes <= *node_size);
+ page = Page::FromAddress(node->address());
+ page->add_available_in_large_free_list(-(*node_size));
+ }
+ }
+
+ ASSERT(IsVeryLong() || available() == SumFreeLists());
return node;
}
@@ -2852,7 +2897,7 @@
void PropertyCellSpace::VerifyObject(HeapObject* object) {
// The object should be a global object property cell or a free-list node.
- CHECK(object->IsJSGlobalPropertyCell() ||
+ CHECK(object->IsPropertyCell() ||
object->map() == heap()->two_pointer_filler_map());
}
diff --git a/src/spaces.h b/src/spaces.h
index ca61081..5b27542 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1454,6 +1454,7 @@
void Free(FreeListNode* node, int size_in_bytes);
FreeListNode* PickNodeFromList(int *node_size);
+ FreeListNode* PickNodeFromList(int size_in_bytes, int *node_size);
intptr_t EvictFreeListItemsInList(Page* p);
@@ -2659,14 +2660,14 @@
// Creates a property cell space object with a maximum capacity.
PropertyCellSpace(Heap* heap, intptr_t max_capacity,
AllocationSpace id)
- : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize)
+ : FixedSpace(heap, max_capacity, id, PropertyCell::kSize)
{}
virtual int RoundSizeDownToObjectAlignment(int size) {
- if (IsPowerOf2(JSGlobalPropertyCell::kSize)) {
- return RoundDown(size, JSGlobalPropertyCell::kSize);
+ if (IsPowerOf2(PropertyCell::kSize)) {
+ return RoundDown(size, PropertyCell::kSize);
} else {
- return (size / JSGlobalPropertyCell::kSize) * JSGlobalPropertyCell::kSize;
+ return (size / PropertyCell::kSize) * PropertyCell::kSize;
}
}
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 40a7938..2a27f4f 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -321,7 +321,7 @@
Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name,
Handle<JSObject> receiver,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
bool is_dont_delete) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindIC(name, stub_holder, Code::LOAD_IC, Code::NORMAL);
@@ -497,7 +497,7 @@
Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> receiver,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
StrictModeFlag strict_mode) {
Handle<Code> stub = FindIC(
name, Handle<JSObject>::cast(receiver),
@@ -734,7 +734,7 @@
Handle<Name> name,
Handle<JSObject> receiver,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function) {
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 0c756a1..c085b51 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -140,7 +140,7 @@
Handle<Code> ComputeLoadGlobal(Handle<Name> name,
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
bool is_dont_delete);
// ---
@@ -183,7 +183,7 @@
Handle<Code> ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
StrictModeFlag strict_mode);
Handle<Code> ComputeStoreCallback(Handle<Name> name,
@@ -251,7 +251,7 @@
Handle<Name> name,
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function);
// ---
@@ -765,7 +765,7 @@
Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete);
@@ -890,7 +890,7 @@
Handle<Name> name);
Handle<Code> CompileStoreGlobal(Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> holder,
+ Handle<PropertyCell> holder,
Handle<Name> name);
private:
@@ -1007,7 +1007,7 @@
Handle<Code> CompileCallGlobal(Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name);
diff --git a/src/type-info.cc b/src/type-info.cc
index 7693547..c5bdc9b 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -363,12 +363,8 @@
if (code->is_compare_ic_stub()) {
int stub_minor_key = code->stub_info();
- CompareIC::State left_state, right_state, handler_state;
- ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
- &handler_state, NULL);
- *left_type = CompareIC::StateToType(isolate_, left_state);
- *right_type = CompareIC::StateToType(isolate_, right_state);
- *overall_type = CompareIC::StateToType(isolate_, handler_state, map);
+ CompareIC::StubInfoToType(
+ stub_minor_key, left_type, right_type, overall_type, map, isolate());
} else if (code->is_compare_nil_ic_stub()) {
CompareNilICStub::State state(code->compare_nil_state());
*compare_nil_type = CompareNilICStub::StateToType(isolate_, state, map);
@@ -376,70 +372,34 @@
}
-TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
- Handle<Object> object = GetInfo(expr->UnaryOperationFeedbackId());
- TypeInfo unknown = TypeInfo::Unknown();
- if (!object->IsCode()) return unknown;
+Handle<Type> TypeFeedbackOracle::UnaryType(TypeFeedbackId id) {
+ Handle<Object> object = GetInfo(id);
+ if (!object->IsCode()) return handle(Type::Any(), isolate());
Handle<Code> code = Handle<Code>::cast(object);
ASSERT(code->is_unary_op_stub());
- UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
- code->unary_op_type());
- switch (type) {
- case UnaryOpIC::SMI:
- return TypeInfo::Smi();
- case UnaryOpIC::NUMBER:
- return TypeInfo::Double();
- default:
- return unknown;
- }
+ return UnaryOpIC::TypeInfoToType(
+ static_cast<UnaryOpIC::TypeInfo>(code->unary_op_type()), isolate());
}
-static TypeInfo TypeFromBinaryOpType(BinaryOpIC::TypeInfo binary_type) {
- switch (binary_type) {
- // Uninitialized means never executed.
- case BinaryOpIC::UNINITIALIZED: return TypeInfo::Uninitialized();
- case BinaryOpIC::SMI: return TypeInfo::Smi();
- case BinaryOpIC::INT32: return TypeInfo::Integer32();
- case BinaryOpIC::NUMBER: return TypeInfo::Double();
- case BinaryOpIC::ODDBALL: return TypeInfo::Unknown();
- case BinaryOpIC::STRING: return TypeInfo::String();
- case BinaryOpIC::GENERIC: return TypeInfo::Unknown();
- }
- UNREACHABLE();
- return TypeInfo::Unknown();
-}
-
-
-void TypeFeedbackOracle::BinaryType(BinaryOperation* expr,
- TypeInfo* left,
- TypeInfo* right,
- TypeInfo* result,
+void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
+ Handle<Type>* left,
+ Handle<Type>* right,
+ Handle<Type>* result,
bool* has_fixed_right_arg,
int* fixed_right_arg_value) {
- Handle<Object> object = GetInfo(expr->BinaryOperationFeedbackId());
- TypeInfo unknown = TypeInfo::Unknown();
- if (!object->IsCode()) {
- *left = *right = *result = unknown;
- return;
- }
+ Handle<Object> object = GetInfo(id);
+ *left = *right = *result = handle(Type::Any(), isolate_);
+ if (!object->IsCode()) return;
Handle<Code> code = Handle<Code>::cast(object);
- if (code->is_binary_op_stub()) {
- int minor_key = code->stub_info();
- BinaryOpIC::TypeInfo left_type, right_type, result_type;
- BinaryOpStub::decode_types_from_minor_key(
- minor_key, &left_type, &right_type, &result_type);
- *left = TypeFromBinaryOpType(left_type);
- *right = TypeFromBinaryOpType(right_type);
- *result = TypeFromBinaryOpType(result_type);
- *has_fixed_right_arg =
- BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key);
- *fixed_right_arg_value =
- BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key);
- return;
- }
- // Not a binary op stub.
- *left = *right = *result = unknown;
+ if (!code->is_binary_op_stub()) return;
+
+ int minor_key = code->stub_info();
+ BinaryOpIC::StubInfoToType(minor_key, left, right, result, isolate());
+ *has_fixed_right_arg =
+ BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key);
+ *fixed_right_arg_value =
+ BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key);
}
diff --git a/src/type-info.h b/src/type-info.h
index 1262b31..3c2b831 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -220,7 +220,6 @@
// Forward declarations.
// TODO(rossberg): these should all go away eventually.
class Assignment;
-class BinaryOperation;
class Call;
class CallNew;
class CaseClause;
@@ -231,7 +230,6 @@
class ICStub;
class Property;
class SmallMapList;
-class UnaryOperation;
class ObjectLiteral;
class ObjectLiteralProperty;
@@ -296,11 +294,11 @@
byte ToBooleanTypes(TypeFeedbackId id);
// Get type information for arithmetic operations and compares.
- TypeInfo UnaryType(UnaryOperation* expr);
- void BinaryType(BinaryOperation* expr,
- TypeInfo* left,
- TypeInfo* right,
- TypeInfo* result,
+ Handle<Type> UnaryType(TypeFeedbackId id);
+ void BinaryType(TypeFeedbackId id,
+ Handle<Type>* left,
+ Handle<Type>* right,
+ Handle<Type>* result,
bool* has_fixed_right_arg,
int* fixed_right_arg_value);
diff --git a/src/version.cc b/src/version.cc
index e731392..176d54d 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,11 +34,11 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 19
-#define BUILD_NUMBER 17
+#define BUILD_NUMBER 18
#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
+#define IS_CANDIDATE_VERSION 1
// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 40025d3..8868c7a 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -6636,11 +6636,11 @@
void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : element value to store
- // -- rbx : array literal
- // -- rdi : map of array literal
// -- rcx : element index as smi
- // -- rdx : array literal index in function
// -- rsp[0] : return address
+ // -- rsp[8] : array literal index in function
+ // -- rsp[16]: array literal
+ // clobbers rbx, rdx, rdi
// -----------------------------------
Label element_done;
@@ -6649,6 +6649,11 @@
Label slow_elements;
Label fast_elements;
+ // Get array literal index, array literal and its map.
+ __ movq(rdx, Operand(rsp, 1 * kPointerSize));
+ __ movq(rbx, Operand(rsp, 2 * kPointerSize));
+ __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
+
__ CheckFastElements(rdi, &double_elements);
// FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 4afcadb..e5d190a 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -337,7 +337,7 @@
ASSERT(back_edge_target->is_bound());
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
__ j(positive, &ok, Label::kNear);
@@ -378,7 +378,7 @@
} else if (FLAG_weighted_back_edges) {
int distance = masm_->pc_offset();
weight = Min(kMaxBackEdgeWeight,
- Max(1, distance / kBackEdgeDistanceUnit));
+ Max(1, distance / kCodeSizeMultiplier));
}
EmitProfilingCounterDecrement(weight);
Label ok;
@@ -1812,7 +1812,8 @@
}
if (!result_saved) {
- __ push(rax);
+ __ push(rax); // array literal
+ __ Push(Smi::FromInt(expr->literal_index()));
result_saved = true;
}
VisitForAccumulatorValue(subexpr);
@@ -1821,7 +1822,7 @@
// Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
// cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
+ __ movq(rbx, Operand(rsp, kPointerSize)); // Copy of array literal.
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
// Store the subexpression value in the array's elements.
__ movq(FieldOperand(rbx, offset), result_register());
@@ -1832,10 +1833,7 @@
INLINE_SMI_CHECK);
} else {
// Store the subexpression value in the array's elements.
- __ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
- __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
__ Move(rcx, Smi::FromInt(i));
- __ Move(rdx, Smi::FromInt(expr->literal_index()));
StoreArrayLiteralElementStub stub;
__ CallStub(&stub);
}
@@ -1844,6 +1842,7 @@
}
if (result_saved) {
+ __ addq(rsp, Immediate(kPointerSize)); // literal index
context()->PlugTOS();
} else {
context()->Plug(rax);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index efb41c8..ce91eff 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -1502,8 +1502,8 @@
}
-void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
- StrictModeFlag strict_mode) {
+void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 18958db..1dd27ac 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -469,27 +469,15 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* pushed_arguments_index,
- int* pushed_arguments_count) {
+ Translation* translation) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
- int translation_size = environment->values()->length();
+ int translation_size = environment->translation_size();
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- // Function parameters are arguments to the outermost environment. The
- // arguments index points to the first element of a sequence of tagged
- // values on the stack that represent the arguments. This needs to be
- // kept in sync with the LArgumentsElements implementation.
- *pushed_arguments_index = -environment->parameter_count();
- *pushed_arguments_count = environment->parameter_count();
-
- WriteTranslation(environment->outer(),
- translation,
- pushed_arguments_index,
- pushed_arguments_count);
+ WriteTranslation(environment->outer(), translation);
bool has_closure_id = !info()->closure().is_null() &&
!info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
@@ -521,23 +509,6 @@
break;
}
- // Inlined frames which push their arguments cause the index to be
- // bumped and another stack area to be used for materialization,
- // otherwise actual argument values are unknown for inlined frames.
- bool arguments_known = true;
- int arguments_index = *pushed_arguments_index;
- int arguments_count = *pushed_arguments_count;
- if (environment->entry() != NULL) {
- arguments_known = environment->entry()->arguments_pushed();
- arguments_index = arguments_index < 0
- ? GetStackSlotCount() : arguments_index + arguments_count;
- arguments_count = environment->entry()->arguments_count() + 1;
- if (environment->entry()->arguments_pushed()) {
- *pushed_arguments_index = arguments_index;
- *pushed_arguments_count = arguments_count;
- }
- }
-
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -549,10 +520,7 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
@@ -561,20 +529,36 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false,
- arguments_known,
- arguments_index,
- arguments_count);
+ false);
}
}
+ // TODO(mstarzinger): Introduce marker operands to indicate that this value
+ // is not present and must be reconstructed from the deoptimizer. Currently
+ // this is only used for the arguments object.
+ if (value == NULL) {
+ int arguments_count = environment->values()->length() - translation_size;
+ translation->BeginArgumentsObject(arguments_count);
+ for (int i = 0; i < arguments_count; ++i) {
+ LOperand* value = environment->values()->at(translation_size + i);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsRegister() ||
+ environment->spilled_registers()[value->index()] == NULL);
+ ASSERT(environment->spilled_registers() == NULL ||
+ !value->IsDoubleRegister() ||
+ environment->spilled_double_registers()[value->index()] == NULL);
+ AddToTranslation(translation,
+ value,
+ environment->HasTaggedValueAt(translation_size + i),
+ environment->HasUint32ValueAt(translation_size + i));
+ }
+ continue;
+ }
+
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i),
- arguments_known,
- arguments_index,
- arguments_count);
+ environment->HasUint32ValueAt(i));
}
}
@@ -582,17 +566,8 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count) {
- if (op == NULL) {
- // TODO(twuerthinger): Introduce marker operands to indicate that this value
- // is not present and must be reconstructed from the deoptimizer. Currently
- // this is only used for the arguments object.
- translation->StoreArgumentsObject(
- arguments_known, arguments_index, arguments_count);
- } else if (op->IsStackSlot()) {
+ bool is_uint32) {
+ if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
} else if (is_uint32) {
@@ -697,8 +672,6 @@
int frame_count = 0;
int jsframe_count = 0;
- int args_index = 0;
- int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@@ -706,7 +679,7 @@
}
}
Translation translation(&translations_, frame_count, jsframe_count, zone());
- WriteTranslation(environment, &translation, &args_index, &args_count);
+ WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index c3f99c4..31dd9c4 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -139,10 +139,7 @@
void DoGap(LGap* instr);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment,
- Translation* translation,
- int* arguments_index,
- int* arguments_count);
+ void WriteTranslation(LEnvironment* environment, Translation* translation);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -253,10 +250,7 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32,
- bool arguments_known,
- int arguments_index,
- int arguments_count);
+ bool is_uint32);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index cb0659d..980cb21 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -937,7 +937,7 @@
BailoutId ast_id = hydrogen_env->ast_id();
ASSERT(!ast_id.IsNone() ||
hydrogen_env->frame_type() != JS_FUNCTION);
- int value_count = hydrogen_env->length();
+ int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
LEnvironment* result = new(zone()) LEnvironment(
hydrogen_env->closure(),
hydrogen_env->frame_type(),
@@ -948,13 +948,15 @@
outer,
hydrogen_env->entry(),
zone());
+ bool needs_arguments_object_materialization = false;
int argument_index = *argument_index_accumulator;
- for (int i = 0; i < value_count; ++i) {
+ for (int i = 0; i < hydrogen_env->length(); ++i) {
if (hydrogen_env->is_special_index(i)) continue;
HValue* value = hydrogen_env->values()->at(i);
LOperand* op = NULL;
if (value->IsArgumentsObject()) {
+ needs_arguments_object_materialization = true;
op = NULL;
} else if (value->IsPushArgument()) {
op = new(zone()) LArgument(argument_index++);
@@ -966,6 +968,21 @@
value->CheckFlag(HInstruction::kUint32));
}
+ if (needs_arguments_object_materialization) {
+ HArgumentsObject* arguments = hydrogen_env->entry() == NULL
+ ? graph()->GetArgumentsObject()
+ : hydrogen_env->entry()->arguments_object();
+ ASSERT(arguments->IsLinked());
+ for (int i = 1; i < arguments->arguments_count(); ++i) {
+ HValue* value = arguments->arguments_values()->at(i);
+ ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
+ LOperand* op = UseAny(value);
+ result->AddValue(op,
+ value->representation(),
+ value->CheckFlag(HInstruction::kUint32));
+ }
+ }
+
if (hydrogen_env->frame_type() == JS_FUNCTION) {
*argument_index_accumulator = argument_index;
}
@@ -1368,19 +1385,6 @@
}
-HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
- // A value with an integer representation does not need to be transformed.
- if (dividend->representation().IsInteger32()) {
- return dividend;
- // A change from an integer32 can be replaced by the integer32 value.
- } else if (dividend->IsChange() &&
- HChange::cast(dividend)->from().IsInteger32()) {
- return HChange::cast(dividend)->value();
- }
- return NULL;
-}
-
-
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
if (divisor->IsConstant() &&
HConstant::cast(divisor)->HasInteger32Value()) {
@@ -2525,8 +2529,9 @@
undefined,
instr->inlining_kind(),
instr->undefined_receiver());
- if (instr->arguments_var() != NULL) {
- inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
+ // Only replay binding of arguments object if it wasn't removed from graph.
+ if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
+ inner->Bind(instr->arguments_var(), instr->arguments_object());
}
inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 1121af5..cc73382 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -2590,7 +2590,6 @@
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
- static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
LInstruction* DoMathFloor(HUnaryMathOperation* instr);
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index a2568a4..b6a1d34 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -697,6 +697,8 @@
void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
+ Address thunk_address,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset) {
@@ -737,9 +739,29 @@
PopSafepointRegisters();
}
+
+ Label profiler_disabled;
+ Label end_profiler_check;
+ bool* is_profiling_flag =
+ isolate()->cpu_profiler()->is_profiling_address();
+ STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+ movq(rax, is_profiling_flag, RelocInfo::EXTERNAL_REFERENCE);
+ cmpb(Operand(rax, 0), Immediate(0));
+ j(zero, &profiler_disabled);
+
+ // Third parameter is the address of the actual getter function.
+ movq(thunk_last_arg, function_address, RelocInfo::EXTERNAL_REFERENCE);
+ movq(rax, thunk_address, RelocInfo::EXTERNAL_REFERENCE);
+ jmp(&end_profiler_check);
+
+ bind(&profiler_disabled);
// Call the api function!
movq(rax, reinterpret_cast<int64_t>(function_address),
RelocInfo::EXTERNAL_REFERENCE);
+
+ bind(&end_profiler_check);
+
+ // Call the api function!
call(rax);
if (FLAG_log_timer_events) {
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 7b8747c..1b7e586 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1239,6 +1239,8 @@
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address,
+ Address thunk_address,
+ Register thunk_last_arg,
int stack_space,
bool returns_handle,
int return_value_offset_from_rbp);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index c105905..79a158c 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -491,11 +491,14 @@
#if defined(__MINGW64__)
Register arguments_arg = rcx;
+ Register callback_arg = rdx;
#elif defined(_WIN64)
// Win64 uses first register--rcx--for returned value.
Register arguments_arg = returns_handle ? rdx : rcx;
+ Register callback_arg = returns_handle ? r8 : rdx;
#else
Register arguments_arg = rdi;
+ Register callback_arg = rsi;
#endif
// Allocate the v8::Arguments structure in the arguments' space since
@@ -514,7 +517,13 @@
// v8::InvocationCallback's argument.
__ lea(arguments_arg, StackSpaceOperand(0));
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeInvocationCallback)
+ : FUNCTION_ADDR(&InvokeFunctionCallback);
+
__ CallApiFunctionAndReturn(function_address,
+ thunk_address,
+ callback_arg,
argc + kFastApiCallArguments + 1,
returns_handle,
kFastApiCallArguments + 1);
@@ -737,7 +746,7 @@
Handle<Name> name,
Register scratch,
Label* miss) {
- Handle<JSGlobalPropertyCell> cell =
+ Handle<PropertyCell> cell =
GlobalObject::EnsurePropertyCell(global, name);
ASSERT(cell->value()->IsTheHole());
__ Move(scratch, cell);
@@ -817,7 +826,13 @@
Register storage_reg = name_reg;
- if (FLAG_track_fields && representation.IsSmi()) {
+ if (details.type() == CONSTANT_FUNCTION) {
+ Handle<HeapObject> constant(
+ HeapObject::cast(descriptors->GetValue(descriptor)));
+ __ LoadHeapObject(scratch1, constant);
+ __ cmpq(value_reg, scratch1);
+ __ j(not_equal, miss_restore_name);
+ } else if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
@@ -844,7 +859,8 @@
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
// Perform map transition for the receiver if necessary.
- if (object->map()->unused_property_fields() == 0) {
+ if (details.type() == FIELD &&
+ object->map()->unused_property_fields() == 0) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
__ pop(scratch1); // Return address.
@@ -873,6 +889,12 @@
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ if (details.type() == CONSTANT_FUNCTION) {
+ ASSERT(value_reg.is(rax));
+ __ ret(0);
+ return;
+ }
+
int index = transition->instance_descriptors()->GetFieldIndex(
transition->LastAdded());
@@ -1318,13 +1340,16 @@
!CallbackTable::ReturnsVoid(isolate(), getter_address);
#if defined(__MINGW64__)
+ Register getter_arg = r8;
Register accessor_info_arg = rdx;
Register name_arg = rcx;
#elif defined(_WIN64)
// Win64 uses first register--rcx--for returned value.
+ Register getter_arg = returns_handle ? r9 : r8;
Register accessor_info_arg = returns_handle ? r8 : rdx;
Register name_arg = returns_handle ? rdx : rcx;
#else
+ Register getter_arg = rdx;
Register accessor_info_arg = rsi;
Register name_arg = rdi;
#endif
@@ -1350,7 +1375,13 @@
// could be used to pass arguments.
__ lea(accessor_info_arg, StackSpaceOperand(0));
+ Address thunk_address = returns_handle
+ ? FUNCTION_ADDR(&InvokeAccessorGetter)
+ : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+
__ CallApiFunctionAndReturn(getter_address,
+ thunk_address,
+ getter_arg,
kStackSpace,
returns_handle,
5);
@@ -2445,7 +2476,7 @@
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
- Handle<JSGlobalPropertyCell>::null(),
+ Handle<PropertyCell>::null(),
function, Handle<String>::cast(name));
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
@@ -2525,7 +2556,7 @@
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
// ----------- S t a t e -------------
@@ -2708,7 +2739,7 @@
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
Handle<GlobalObject> object,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name) {
Label miss;
@@ -2720,7 +2751,7 @@
// Compute the cell operand to use.
__ Move(scratch1(), cell);
Operand cell_operand =
- FieldOperand(scratch1(), JSGlobalPropertyCell::kValueOffset);
+ FieldOperand(scratch1(), PropertyCell::kValueOffset);
// Check that the value in the cell is not the hole. If it is, this
// cell could have been deleted and reintroducing the global needs
@@ -2888,7 +2919,7 @@
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<GlobalObject> global,
- Handle<JSGlobalPropertyCell> cell,
+ Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
@@ -2902,7 +2933,7 @@
// Get the value from the cell.
__ Move(rbx, cell);
- __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
+ __ movq(rbx, FieldOperand(rbx, PropertyCell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {