@@ -125,23 +125,31 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)

#ifdef DEBUG

#define BUILTIN(name) \
MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
name##ArgumentsType args, Isolate* isolate); \
MUST_USE_RESULT static MaybeObject* Builtin_##name( \
name##ArgumentsType args, Isolate* isolate) { \
ASSERT(isolate == Isolate::Current()); \
args.Verify(); \
return Builtin_Impl_##name(args, isolate); \
} \
MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
#define BUILTIN(name) \
MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
name##ArgumentsType args, Isolate* isolate); \
MUST_USE_RESULT static MaybeObject* Builtin_##name( \
int args_length, Object** args_object, Isolate* isolate) { \
name##ArgumentsType args(args_length, args_object); \
ASSERT(isolate == Isolate::Current()); \
args.Verify(); \
return Builtin_Impl_##name(args, isolate); \
} \
MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
name##ArgumentsType args, Isolate* isolate)

#else // For release mode.

#define BUILTIN(name) \
static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)

#define BUILTIN(name) \
static MaybeObject* Builtin_impl##name( \
name##ArgumentsType args, Isolate* isolate); \
static MaybeObject* Builtin_##name( \
int args_length, Object** args_object, Isolate* isolate) { \
name##ArgumentsType args(args_length, args_object); \
return Builtin_impl##name(args, isolate); \
} \
static MaybeObject* Builtin_impl##name( \
name##ArgumentsType args, Isolate* isolate)
#endif


@@ -186,55 +194,58 @@ BUILTIN(EmptyFunction) {
}


#define CONVERT_ARG_STUB_CALLER_ARGS(name) \
Arguments* name = reinterpret_cast<Arguments*>(args[0]);


RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) {
CONVERT_ARG_STUB_CALLER_ARGS(caller_args);
ASSERT(args.length() == 2);
Handle<Object> type_info = args.at<Object>(1);
// If we get 2 arguments then they are the stub parameters (constructor, type
// info). If we get 3, then the first one is a pointer to the arguments
// passed by the caller.
Arguments empty_args(0, NULL);
bool no_caller_args = args.length() == 2;
ASSERT(no_caller_args || args.length() == 3);
int parameters_start = no_caller_args ? 0 : 1;
Arguments* caller_args = no_caller_args
? &empty_args
: reinterpret_cast<Arguments*>(args[0]);
Handle<JSFunction> constructor = args.at<JSFunction>(parameters_start);
Handle<Object> type_info = args.at<Object>(parameters_start + 1);

JSArray* array = NULL;
bool holey = false;
if (caller_args->length() == 1 && (*caller_args)[0]->IsSmi()) {
int value = Smi::cast((*caller_args)[0])->value();
holey = (value > 0 && value < JSObject::kInitialMaxFastElementArray);
}

JSArray* array;
MaybeObject* maybe_array;
if (*type_info != isolate->heap()->undefined_value()) {
if (*type_info != isolate->heap()->undefined_value() &&
JSGlobalPropertyCell::cast(*type_info)->value()->IsSmi()) {
JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(*type_info);
if (cell->value()->IsSmi()) {
Smi* smi = Smi::cast(cell->value());
ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
if (holey && !IsFastHoleyElementsKind(to_kind)) {
to_kind = GetHoleyElementsKind(to_kind);
// Update the allocation site info to reflect the advice alteration.
cell->set_value(Smi::FromInt(to_kind));
}

AllocationSiteMode mode = AllocationSiteInfo::GetMode(to_kind);
if (mode == TRACK_ALLOCATION_SITE) {
maybe_array = isolate->heap()->AllocateEmptyJSArrayWithAllocationSite(
to_kind, type_info);
} else {
maybe_array = isolate->heap()->AllocateEmptyJSArray(to_kind);
}
if (!maybe_array->To(&array)) return maybe_array;
Smi* smi = Smi::cast(cell->value());
ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
if (holey && !IsFastHoleyElementsKind(to_kind)) {
to_kind = GetHoleyElementsKind(to_kind);
// Update the allocation site info to reflect the advice alteration.
cell->set_value(Smi::FromInt(to_kind));
}
}

ElementsKind kind = GetInitialFastElementsKind();
if (holey) {
kind = GetHoleyElementsKind(kind);
}

if (array == NULL) {
maybe_array = isolate->heap()->AllocateEmptyJSArray(kind);
maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
*constructor, type_info);
if (!maybe_array->To(&array)) return maybe_array;
} else {
ElementsKind kind = constructor->initial_map()->elements_kind();
ASSERT(kind == GetInitialFastElementsKind());
maybe_array = isolate->heap()->AllocateJSObject(*constructor);
if (!maybe_array->To(&array)) return maybe_array;
// We might need to transition to holey
if (holey) {
kind = GetHoleyElementsKind(kind);
maybe_array = array->TransitionElementsKind(kind);
if (maybe_array->IsFailure()) return maybe_array;
}
}

maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
DONT_INITIALIZE_ARRAY_ELEMENTS);
if (maybe_array->IsFailure()) return maybe_array;
maybe_array = ArrayConstructInitializeElements(array, caller_args);
if (maybe_array->IsFailure()) return maybe_array;
return array;
@@ -1500,6 +1511,11 @@ static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
KeyedLoadIC::GenerateNonStrictArguments(masm);
}

static void Generate_StoreIC_Slow(MacroAssembler* masm) {
StoreIC::GenerateSlow(masm);
}


static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
StoreIC::GenerateInitialize(masm);
}
@@ -1617,6 +1633,11 @@ static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
}


static void Generate_CompareNilIC_DebugBreak(MacroAssembler* masm) {
Debug::GenerateCompareNilICDebugBreak(masm);
}


static void Generate_Return_DebugBreak(MacroAssembler* masm) {
Debug::GenerateReturnDebugBreak(masm);
}
@@ -124,6 +124,8 @@ enum BuiltinExtraArguments {
Code::kNoExtraICState) \
V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(StoreIC_Slow, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedStoreIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
@@ -230,6 +232,8 @@ enum BuiltinExtraArguments {
DEBUG_BREAK) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_STUB, \
DEBUG_BREAK) \
V(CompareNilIC_DebugBreak, COMPARE_NIL_IC, DEBUG_STUB, \
DEBUG_BREAK) \
V(Slot_DebugBreak, BUILTIN, DEBUG_STUB, \
DEBUG_BREAK) \
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_STUB, \
@@ -274,8 +278,6 @@ enum BuiltinExtraArguments {
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)

MaybeObject* ArrayConstructor_StubFailure(Arguments args, Isolate* isolate);

class BuiltinFunctionTable;
class ObjectVisitor;

@@ -82,6 +82,24 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
HContext* context() { return context_; }
Isolate* isolate() { return info_.isolate(); }

class ArrayContextChecker {
public:
ArrayContextChecker(HGraphBuilder* builder, HValue* constructor,
HValue* array_function)
: checker_(builder) {
checker_.If<HCompareObjectEqAndBranch, HValue*>(constructor,
array_function);
checker_.Then();
}

~ArrayContextChecker() {
checker_.ElseDeopt();
checker_.End();
}
private:
IfBuilder checker_;
};

private:
SmartArrayPointer<HParameter*> parameters_;
HValue* arguments_length_;
@@ -240,7 +258,8 @@ Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) {
GetCodeKind(),
GetICState(),
GetExtraICState(),
GetStubType(), -1);
GetStubType(),
GetStubFlags());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
return new_object;
@@ -290,8 +309,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
checker.Then();

if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
HValue* elements =
AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
HValue* elements = AddLoadElements(boilerplate);

IfBuilder if_fixed_cow(this);
if_fixed_cow.IfCompareMap(elements, factory->fixed_cow_array_map());
@@ -377,11 +395,12 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {

for (int i = 0; i < size; i += kPointerSize) {
HInstruction* value =
AddInstruction(new(zone) HLoadNamedField(boilerplate, true, i));
AddInstruction(new(zone) HLoadNamedField(
boilerplate, true, Representation::Tagged(), i));
AddInstruction(new(zone) HStoreNamedField(object,
factory->empty_string(),
value,
true, i));
value, true,
Representation::Tagged(), i));
}

checker.ElseDeopt();
@@ -409,6 +428,36 @@ Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
}


template<>
HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
Representation representation = casted_stub()->representation();
HInstruction* load = AddInstruction(DoBuildLoadNamedField(
GetParameter(0), casted_stub()->is_inobject(),
representation, casted_stub()->offset()));
return load;
}


Handle<Code> LoadFieldStub::GenerateCode() {
return DoGenerateCode(this);
}


template<>
HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
Representation representation = casted_stub()->representation();
HInstruction* load = AddInstruction(DoBuildLoadNamedField(
GetParameter(0), casted_stub()->is_inobject(),
representation, casted_stub()->offset()));
return load;
}


Handle<Code> KeyedLoadFieldStub::GenerateCode() {
return DoGenerateCode(this);
}


template <>
HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
BuildUncheckedMonomorphicElementAccess(
@@ -452,8 +501,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {

if_builder.Else();

HInstruction* elements =
AddInstruction(new(zone) HLoadElements(js_array, js_array));
HInstruction* elements = AddLoadElements(js_array);

HInstruction* elements_length =
AddInstruction(new(zone) HFixedArrayBaseLength(elements));
@@ -470,12 +518,15 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
AddInstruction(new(zone) HStoreNamedField(js_array,
factory->elements_field_string(),
new_elements, true,
Representation::Tagged(),
JSArray::kElementsOffset));

if_builder.End();

AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_string(),
map, true, JSArray::kMapOffset));
map, true,
Representation::Tagged(),
JSArray::kMapOffset));
return js_array;
}

@@ -491,6 +542,10 @@ HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
// -- Parameter 1 : type info cell
// -- Parameter 0 : constructor
// -----------------------------------
HInstruction* array_function = BuildGetArrayFunction(context());
ArrayContextChecker(this,
GetParameter(ArrayConstructorStubBase::kConstructor),
array_function);
// Get the right map
// Should be a constant
JSArrayBuilder array_builder(
@@ -510,6 +565,10 @@ Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() {
template <>
HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
BuildCodeStub() {
HInstruction* array_function = BuildGetArrayFunction(context());
ArrayContextChecker(this,
GetParameter(ArrayConstructorStubBase::kConstructor),
array_function);
// Smi check and range check on the input arg.
HValue* constant_one = graph()->GetConstant1();
HValue* constant_zero = graph()->GetConstant0();
@@ -563,6 +622,10 @@ Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {

template <>
HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
HInstruction* array_function = BuildGetArrayFunction(context());
ArrayContextChecker(this,
GetParameter(ArrayConstructorStubBase::kConstructor),
array_function);
ElementsKind kind = casted_stub()->elements_kind();
HValue* length = GetArgumentsLength();

@@ -431,7 +431,9 @@ CompareNilICStub::Types CompareNilICStub::GetPatchedICFlags(
} else if (object->IsUndefined()) {
types = static_cast<CompareNilICStub::Types>(
types | CompareNilICStub::kCompareAgainstUndefined);
} else if (object->IsUndetectableObject() || !object->IsHeapObject()) {
} else if (object->IsUndetectableObject() ||
object->IsOddball() ||
!object->IsHeapObject()) {
types = CompareNilICStub::kFullCompare;
} else if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) {
types = CompareNilICStub::kFullCompare;
@@ -87,7 +87,8 @@ namespace internal {
V(ArrayConstructor) \
V(ProfileEntryHook) \
/* IC Handler stubs */ \
V(LoadField)
V(LoadField) \
V(KeyedLoadField)

// List of code stubs only used on ARM platforms.
#ifdef V8_TARGET_ARCH_ARM
@@ -185,16 +186,19 @@ class CodeStub BASE_EMBEDDED {
virtual Code::ExtraICState GetExtraICState() {
return Code::kNoExtraICState;
}
virtual Code::StubType GetStubType() {
return Code::NORMAL;
}
virtual int GetStubFlags() {
return -1;
}

protected:
static bool CanUseFPRegisters();

// Generates the assembler code for the stub.
virtual Handle<Code> GenerateCode() = 0;

virtual Code::StubType GetStubType() {
return Code::NORMAL;
}

// Returns whether the code generated for this stub needs to be allocated as
// a fixed (non-moveable) code object.
@@ -253,7 +257,6 @@ class PlatformCodeStub : public CodeStub {
virtual Handle<Code> GenerateCode();

virtual Code::Kind GetCodeKind() const { return Code::STUB; }
virtual int GetStubFlags() { return -1; }

protected:
// Generates the assembler code for the stub.
@@ -754,42 +757,108 @@ class StoreArrayLengthStub: public StoreICStub {
};


class HandlerStub: public ICStub {
class HICStub: public HydrogenCodeStub {
public:
virtual Code::Kind GetCodeKind() const { return kind(); }
virtual InlineCacheState GetICState() { return MONOMORPHIC; }

protected:
HICStub() : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) { }
class KindBits: public BitField<Code::Kind, 0, 4> {};
virtual Code::Kind kind() const = 0;
};


class HandlerStub: public HICStub {
public:
explicit HandlerStub(Code::Kind kind) : ICStub(kind) { }
virtual Code::Kind GetCodeKind() const { return Code::STUB; }
virtual int GetStubFlags() { return kind(); }

protected:
HandlerStub() : HICStub() { }
};


class LoadFieldStub: public HandlerStub {
public:
LoadFieldStub(Register reg, bool inobject, int index)
: HandlerStub(Code::LOAD_IC),
reg_(reg),
inobject_(inobject),
index_(index) { }
virtual void Generate(MacroAssembler* masm);
LoadFieldStub(bool inobject, int index, Representation representation)
: HandlerStub() {
Initialize(Code::LOAD_IC, inobject, index, representation);
}

virtual Handle<Code> GenerateCode();

virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);

Representation representation() {
if (unboxed_double()) return Representation::Double();
return Representation::Tagged();
}

virtual Code::Kind kind() const {
return KindBits::decode(bit_field_);
}

bool is_inobject() {
return InobjectBits::decode(bit_field_);
}

int offset() {
int index = IndexBits::decode(bit_field_);
int offset = index * kPointerSize;
if (is_inobject()) return offset;
return FixedArray::kHeaderSize + offset;
}

bool unboxed_double() {
return UnboxedDoubleBits::decode(bit_field_);
}

protected:
virtual Code::StubType GetStubType() { return Code::FIELD; }

protected:
LoadFieldStub() : HandlerStub() { }

void Initialize(Code::Kind kind,
bool inobject,
int index,
Representation representation) {
bool unboxed_double = FLAG_track_double_fields && representation.IsDouble();
bit_field_ = KindBits::encode(kind)
| InobjectBits::encode(inobject)
| IndexBits::encode(index)
| UnboxedDoubleBits::encode(unboxed_double);
}

private:
STATIC_ASSERT(KindBits::kSize == 4);
class RegisterBits: public BitField<int, 4, 6> {};
class InobjectBits: public BitField<bool, 10, 1> {};
class IndexBits: public BitField<int, 11, 11> {};
class InobjectBits: public BitField<bool, 4, 1> {};
class IndexBits: public BitField<int, 5, 11> {};
class UnboxedDoubleBits: public BitField<bool, 16, 1> {};
virtual CodeStub::Major MajorKey() { return LoadField; }
virtual int MinorKey() {
return KindBits::encode(kind())
| RegisterBits::encode(reg_.code())
| InobjectBits::encode(inobject_)
| IndexBits::encode(index_);
virtual int NotMissMinorKey() { return bit_field_; }

int bit_field_;
};


class KeyedLoadFieldStub: public LoadFieldStub {
public:
KeyedLoadFieldStub(bool inobject, int index, Representation representation)
: LoadFieldStub() {
Initialize(Code::KEYED_LOAD_IC, inobject, index, representation);
}

Register reg_;
bool inobject_;
int index_;
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);

virtual Handle<Code> GenerateCode();

private:
virtual CodeStub::Major MajorKey() { return KeyedLoadField; }
};


@@ -1596,7 +1665,8 @@ class ArrayConstructorStubBase : public HydrogenCodeStub {
static void InstallDescriptors(Isolate* isolate);

// Parameters accessed via CodeStubGraphBuilder::GetParameter()
static const int kPropertyCell = 0;
static const int kConstructor = 0;
static const int kPropertyCell = 1;

private:
int NotMissMinorKey() { return bit_field_; }
@@ -144,7 +144,8 @@ Code::Flags CompilationInfo::flags() const {
return Code::ComputeFlags(code_stub()->GetCodeKind(),
code_stub()->GetICState(),
code_stub()->GetExtraICState(),
Code::NORMAL, -1);
code_stub()->GetStubType(),
code_stub()->GetStubFlags());
} else {
return Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
}
@@ -299,14 +300,14 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
//
// The encoding is as a signed value, with parameters and receiver using
// the negative indices and locals the non-negative ones.
const int parameter_limit = -LUnallocated::kMinFixedIndex;
const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
Scope* scope = info()->scope();
if ((scope->num_parameters() + 1) > parameter_limit) {
info()->set_bailout_reason("too many parameters");
return AbortOptimization();
}

const int locals_limit = LUnallocated::kMaxFixedIndex;
const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
if (!info()->osr_ast_id().IsNone() &&
scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
info()->set_bailout_reason("too many parameters/locals");
@@ -124,6 +124,15 @@ enum BindingFlags {
V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(UINT8_ARRAY_FUN_INDEX, JSFunction, uint8_array_fun) \
V(INT8_ARRAY_FUN_INDEX, JSFunction, int8_array_fun) \
V(UINT16_ARRAY_FUN_INDEX, JSFunction, uint16_array_fun) \
V(INT16_ARRAY_FUN_INDEX, JSFunction, int16_array_fun) \
V(UINT32_ARRAY_FUN_INDEX, JSFunction, uint32_array_fun) \
V(INT32_ARRAY_FUN_INDEX, JSFunction, int32_array_fun) \
V(FLOAT_ARRAY_FUN_INDEX, JSFunction, float_array_fun) \
V(DOUBLE_ARRAY_FUN_INDEX, JSFunction, double_array_fun) \
V(UINT8C_ARRAY_FUN_INDEX, JSFunction, uint8c_array_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
@@ -171,6 +180,7 @@ enum BindingFlags {
strict_mode_generator_function_map) \
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
generator_object_prototype_map) \
V(GENERATOR_RESULT_MAP_INDEX, Map, generator_result_map) \
V(RANDOM_SEED_INDEX, ByteArray, random_seed)

// JSFunctions are pairs (context, function code), sometimes also called
@@ -278,6 +288,15 @@ class Context: public FixedArray {
INSTANTIATE_FUN_INDEX,
CONFIGURE_INSTANCE_FUN_INDEX,
ARRAY_BUFFER_FUN_INDEX,
UINT8_ARRAY_FUN_INDEX,
INT8_ARRAY_FUN_INDEX,
UINT16_ARRAY_FUN_INDEX,
INT16_ARRAY_FUN_INDEX,
UINT32_ARRAY_FUN_INDEX,
INT32_ARRAY_FUN_INDEX,
FLOAT_ARRAY_FUN_INDEX,
DOUBLE_ARRAY_FUN_INDEX,
UINT8C_ARRAY_FUN_INDEX,
MESSAGE_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,
@@ -305,6 +324,7 @@ class Context: public FixedArray {
GENERATOR_FUNCTION_MAP_INDEX,
STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
GENERATOR_RESULT_MAP_INDEX,
RANDOM_SEED_INDEX,

// Properties from here are treated as weak references by the full GC.
@@ -77,7 +77,7 @@ void HandleDebugEvent(DebugEvent event,

// Print the event details.
Handle<Object> details =
Shell::DebugMessageDetails(Handle<String>::Cast(event_json));
Shell::DebugMessageDetails(isolate, Handle<String>::Cast(event_json));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate, &try_catch);
return;
@@ -114,7 +114,7 @@ void HandleDebugEvent(DebugEvent event,

// Convert the debugger command to a JSON debugger request.
Handle<Value> request =
Shell::DebugCommandToJSONRequest(String::New(command));
Shell::DebugCommandToJSONRequest(isolate, String::New(command));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate, &try_catch);
continue;
@@ -146,7 +146,8 @@ void HandleDebugEvent(DebugEvent event,
Handle<String> response = Handle<String>::Cast(response_val);

// Convert the debugger response into text details and the running state.
Handle<Object> response_details = Shell::DebugMessageDetails(response);
Handle<Object> response_details =
Shell::DebugMessageDetails(isolate, response);
if (try_catch.HasCaught()) {
Shell::ReportException(isolate, &try_catch);
continue;
@@ -281,7 +282,8 @@ void RemoteDebugger::HandleMessageReceived(char* message) {
// Print the event details.
TryCatch try_catch;
Handle<Object> details =
Shell::DebugMessageDetails(Handle<String>::Cast(String::New(message)));
Shell::DebugMessageDetails(isolate_,
Handle<String>::Cast(String::New(message)));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
@@ -310,7 +312,7 @@ void RemoteDebugger::HandleKeyboardCommand(char* command) {
// Convert the debugger command to a JSON debugger request.
TryCatch try_catch;
Handle<Value> request =
Shell::DebugCommandToJSONRequest(String::New(command));
Shell::DebugCommandToJSONRequest(isolate_, String::New(command));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
@@ -40,6 +40,11 @@
#include <string.h>
#include <sys/stat.h>

// TODO(dcarney): remove
#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT

#ifdef V8_SHARED
#include <assert.h>
#endif // V8_SHARED
@@ -124,8 +129,8 @@ class PerIsolateData {
}

#define DEFINE_STRING_GETTER(name, value) \
static Persistent<String> name##_string(Isolate* isolate) { \
return Get(isolate)->name##_string_; \
static Handle<String> name##_string(Isolate* isolate) { \
return Handle<String>(*Get(isolate)->name##_string_); \
}
FOR_EACH_STRING(DEFINE_STRING_GETTER)
#undef DEFINE_STRING_GETTER
@@ -245,7 +250,7 @@ bool Shell::ExecuteString(Isolate* isolate,
} else {
PerIsolateData* data = PerIsolateData::Get(isolate);
Local<Context> realm =
Local<Context>::New(data->realms_[data->realm_current_]);
Local<Context>::New(isolate, data->realms_[data->realm_current_]);
realm->Enter();
Handle<Value> result = script->Run();
realm->Exit();
@@ -272,7 +277,7 @@ bool Shell::ExecuteString(Isolate* isolate,
#if !defined(V8_SHARED)
} else {
v8::TryCatch try_catch;
Context::Scope context_scope(utility_context_);
Context::Scope context_scope(isolate, utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("Stringify"));
Handle<Value> argv[1] = { result };
@@ -421,7 +426,7 @@ Handle<Value> Shell::RealmEval(const Arguments& args) {
}
Handle<Script> script = Script::New(args[1]->ToString());
if (script.IsEmpty()) return Undefined(isolate);
Local<Context> realm = Local<Context>::New(data->realms_[index]);
Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
realm->Enter();
Handle<Value> result = script->Run();
realm->Exit();
@@ -435,7 +440,7 @@ Handle<Value> Shell::RealmSharedGet(Local<String> property,
Isolate* isolate = info.GetIsolate();
PerIsolateData* data = PerIsolateData::Get(isolate);
if (data->realm_shared_.IsEmpty()) return Undefined(isolate);
return data->realm_shared_;
return Local<Value>::New(isolate, data->realm_shared_);
}

void Shell::RealmSharedSet(Local<String> property,
@@ -1057,14 +1062,14 @@ Handle<Value> Shell::ArraySet(const Arguments& args) {


void Shell::ExternalArrayWeakCallback(v8::Isolate* isolate,
Persistent<Value> object,
void* data) {
Persistent<Object>* object,
uint8_t* data) {
HandleScope scope(isolate);
int32_t length = object->ToObject()->Get(
int32_t length = (*object)->Get(
PerIsolateData::byteLength_string(isolate))->Uint32Value();
isolate->AdjustAmountOfExternalAllocatedMemory(-length);
delete[] static_cast<uint8_t*>(data);
object.Dispose(isolate);
delete[] data;
object->Dispose(isolate);
}


@@ -1180,7 +1185,7 @@ Handle<Array> Shell::GetCompletions(Isolate* isolate,
Handle<String> text,
Handle<String> full) {
HandleScope handle_scope(isolate);
Context::Scope context_scope(utility_context_);
Context::Scope context_scope(isolate, utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("GetCompletions"));
static const int kArgc = 3;
@@ -1191,8 +1196,10 @@ Handle<Array> Shell::GetCompletions(Isolate* isolate,


#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
Context::Scope context_scope(utility_context_);
Handle<Object> Shell::DebugMessageDetails(Isolate* isolate,
Handle<String> message) {
HandleScope handle_scope(isolate);
Context::Scope context_scope(isolate, utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
static const int kArgc = 1;
@@ -1202,8 +1209,10 @@ Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
}


Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
Context::Scope context_scope(utility_context_);
Handle<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
Handle<String> command) {
HandleScope handle_scope(isolate);
Context::Scope context_scope(isolate, utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
static const int kArgc = 1;
@@ -1214,7 +1223,9 @@ Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {


void Shell::DispatchDebugMessages() {
v8::Context::Scope scope(Shell::evaluation_context_);
Isolate* isolate = v8::Isolate::GetCurrent();
HandleScope handle_scope(isolate);
v8::Context::Scope scope(isolate, Shell::evaluation_context_);
v8::Debug::ProcessDebugMessages();
}
#endif // ENABLE_DEBUGGER_SUPPORT
@@ -1327,7 +1338,7 @@ void Shell::InstallUtilityScript(Isolate* isolate) {
// utility, evaluation and debug context can all access each other.
utility_context_->SetSecurityToken(Undefined(isolate));
evaluation_context_->SetSecurityToken(Undefined(isolate));
Context::Scope utility_scope(utility_context_);
Context::Scope utility_scope(isolate, utility_context_);

#ifdef ENABLE_DEBUGGER_SUPPORT
if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
@@ -1459,28 +1470,34 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
global_template->Set(String::New("Realm"), realm_template);

// Bind the handlers for external arrays.
PropertyAttribute attr =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
global_template->Set(PerIsolateData::ArrayBuffer_string(isolate),
CreateArrayBufferTemplate(ArrayBuffer), attr);
global_template->Set(String::New("Int8Array"),
CreateArrayTemplate(Int8Array), attr);
global_template->Set(String::New("Uint8Array"),
CreateArrayTemplate(Uint8Array), attr);
global_template->Set(String::New("Int16Array"),
CreateArrayTemplate(Int16Array), attr);
global_template->Set(String::New("Uint16Array"),
CreateArrayTemplate(Uint16Array), attr);
global_template->Set(String::New("Int32Array"),
CreateArrayTemplate(Int32Array), attr);
global_template->Set(String::New("Uint32Array"),
CreateArrayTemplate(Uint32Array), attr);
global_template->Set(String::New("Float32Array"),
CreateArrayTemplate(Float32Array), attr);
global_template->Set(String::New("Float64Array"),
CreateArrayTemplate(Float64Array), attr);
global_template->Set(String::New("Uint8ClampedArray"),
CreateArrayTemplate(Uint8ClampedArray), attr);
#ifndef V8_SHARED
if (!i::FLAG_harmony_typed_arrays) {
#endif // V8_SHARED
PropertyAttribute attr =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
global_template->Set(PerIsolateData::ArrayBuffer_string(isolate),
CreateArrayBufferTemplate(ArrayBuffer), attr);
global_template->Set(String::New("Int8Array"),
CreateArrayTemplate(Int8Array), attr);
global_template->Set(String::New("Uint8Array"),
CreateArrayTemplate(Uint8Array), attr);
global_template->Set(String::New("Int16Array"),
CreateArrayTemplate(Int16Array), attr);
global_template->Set(String::New("Uint16Array"),
CreateArrayTemplate(Uint16Array), attr);
global_template->Set(String::New("Int32Array"),
CreateArrayTemplate(Int32Array), attr);
global_template->Set(String::New("Uint32Array"),
CreateArrayTemplate(Uint32Array), attr);
global_template->Set(String::New("Float32Array"),
CreateArrayTemplate(Float32Array), attr);
global_template->Set(String::New("Float64Array"),
CreateArrayTemplate(Float64Array), attr);
global_template->Set(String::New("Uint8ClampedArray"),
CreateArrayTemplate(Uint8ClampedArray), attr);
#ifndef V8_SHARED
}
#endif // V8_SHARED

#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
@@ -1522,7 +1539,8 @@ void Shell::InitializeDebugger(Isolate* isolate) {
Locker lock(isolate);
HandleScope scope(isolate);
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
utility_context_ = Context::New(NULL, global_template);
utility_context_.Reset(isolate,
Context::New(isolate, NULL, global_template));

#ifdef ENABLE_DEBUGGER_SUPPORT
// Start the debugger agent if requested.
@@ -1535,14 +1553,15 @@ void Shell::InitializeDebugger(Isolate* isolate) {
}


Persistent<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
#ifndef V8_SHARED
// This needs to be a critical section since this is not thread-safe
i::ScopedLock lock(context_mutex_);
#endif // V8_SHARED
// Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Persistent<Context> context = Context::New(NULL, global_template);
HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate, NULL, global_template);
ASSERT(!context.IsEmpty());
Context::Scope scope(context);

@@ -1560,7 +1579,7 @@ Persistent<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
context->Global()->Set(String::New("arguments"),
Utils::ToLocal(arguments_jsarray));
#endif // V8_SHARED
return context;
return handle_scope.Close(context);
}


@@ -1740,9 +1759,9 @@ Handle<String> Shell::ReadFile(Isolate* isolate, const char* name) {

void Shell::RunShell(Isolate* isolate) {
Locker locker(isolate);
Context::Scope context_scope(evaluation_context_);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
HandleScope outer_scope(isolate);
Context::Scope context_scope(isolate, evaluation_context_);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Handle<String> name = String::New("(d8)");
LineEditor* console = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
@@ -1791,7 +1810,7 @@ void ShellThread::Run() {
// Prepare the context for this thread.
Locker locker(isolate_);
HandleScope outer_scope(isolate_);
Persistent<Context> thread_context =
Local<Context> thread_context =
Shell::CreateEvaluationContext(isolate_);
Context::Scope context_scope(thread_context);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate_));
@@ -1815,7 +1834,6 @@ void ShellThread::Run() {
Shell::ExecuteString(isolate_, str, String::New(filename), false, false);
}

thread_context.Dispose(thread_context->GetIsolate());
ptr = next_line;
}
}
@@ -1892,15 +1910,16 @@ void SourceGroup::ExecuteInThread() {
{
Isolate::Scope iscope(isolate);
Locker lock(isolate);
HandleScope scope(isolate);
PerIsolateData data(isolate);
Persistent<Context> context = Shell::CreateEvaluationContext(isolate);
{
Context::Scope cscope(context);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Execute(isolate);
HandleScope scope(isolate);
PerIsolateData data(isolate);
Local<Context> context = Shell::CreateEvaluationContext(isolate);
{
Context::Scope cscope(context);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Execute(isolate);
}
}
context.Dispose(isolate);
if (Shell::options.send_idle_notification) {
const int kLongIdlePauseInMs = 1000;
V8::ContextDisposedNotification();
@@ -2091,26 +2110,27 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
#endif // V8_SHARED
{ // NOLINT
Locker lock(isolate);
HandleScope scope(isolate);
Persistent<Context> context = CreateEvaluationContext(isolate);
if (options.last_run) {
// Keep using the same context in the interactive shell.
evaluation_context_ = context;
{
HandleScope scope(isolate);
Local<Context> context = CreateEvaluationContext(isolate);
if (options.last_run) {
// Keep using the same context in the interactive shell.
evaluation_context_.Reset(isolate, context);
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
// If the interactive debugger is enabled make sure to activate
// it before running the files passed on the command line.
if (i::FLAG_debugger) {
InstallUtilityScript(isolate);
}
// If the interactive debugger is enabled make sure to activate
// it before running the files passed on the command line.
if (i::FLAG_debugger) {
InstallUtilityScript(isolate);
}
#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
}
{
Context::Scope cscope(context);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
options.isolate_sources[0].Execute(isolate);
}
{
Context::Scope cscope(context);
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
options.isolate_sources[0].Execute(isolate);
}
}
if (!options.last_run) {
context.Dispose(isolate);
if (options.send_idle_notification) {
const int kLongIdlePauseInMs = 1000;
V8::ContextDisposedNotification();
@@ -2155,7 +2175,7 @@ int Shell::Main(int argc, char* argv[]) {
{
Initialize(isolate);
#ifdef ENABLE_VTUNE_JIT_INTERFACE
vTune::InitilizeVtuneForV8();
vTune::InitializeVtuneForV8();
#endif
PerIsolateData data(isolate);
InitializeDebugger(isolate);
@@ -273,7 +273,7 @@ class Shell : public i::AllStatic {
static const char* ToCString(const v8::String::Utf8Value& value);
static void ReportException(Isolate* isolate, TryCatch* try_catch);
static Handle<String> ReadFile(Isolate* isolate, const char* name);
static Persistent<Context> CreateEvaluationContext(Isolate* isolate);
static Local<Context> CreateEvaluationContext(Isolate* isolate);
static int RunMain(Isolate* isolate, int argc, char* argv[]);
static int Main(int argc, char* argv[]);
static void Exit(int exit_code);
@@ -292,8 +292,10 @@ class Shell : public i::AllStatic {
static void MapCounters(const char* name);

#ifdef ENABLE_DEBUGGER_SUPPORT
static Handle<Object> DebugMessageDetails(Handle<String> message);
static Handle<Value> DebugCommandToJSONRequest(Handle<String> command);
static Handle<Object> DebugMessageDetails(Isolate* isolate,
Handle<String> message);
static Handle<Value> DebugCommandToJSONRequest(Isolate* isolate,
Handle<String> command);
static void DispatchDebugMessages();
#endif // ENABLE_DEBUGGER_SUPPORT
#endif // V8_SHARED
@@ -414,8 +416,8 @@ class Shell : public i::AllStatic {
ExternalArrayType type,
int32_t element_size);
static void ExternalArrayWeakCallback(Isolate* isolate,
Persistent<Value> object,
void* data);
Persistent<Object>* object,
uint8_t* data);
};


@@ -76,12 +76,12 @@ Debug::~Debug() {

static void PrintLn(v8::Local<v8::Value> value) {
v8::Local<v8::String> s = value->ToString();
ScopedVector<char> data(s->Length() + 1);
ScopedVector<char> data(s->Utf8Length() + 1);
if (data.start() == NULL) {
V8::FatalProcessOutOfMemory("PrintLn");
return;
}
s->WriteAscii(data.start());
s->WriteUtf8(data.start());
PrintF("%s\n", data.start());
}

@@ -1644,6 +1644,9 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
case Code::KEYED_STORE_IC:
return isolate->builtins()->KeyedStoreIC_DebugBreak();

case Code::COMPARE_NIL_IC:
return isolate->builtins()->CompareNilIC_DebugBreak();

default:
UNREACHABLE();
}
@@ -418,6 +418,7 @@ class Debug {
static void GenerateStoreICDebugBreak(MacroAssembler* masm);
static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
static void GenerateCompareNilICDebugBreak(MacroAssembler* masm);
static void GenerateReturnDebugBreak(MacroAssembler* masm);
static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
static void GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm);
@@ -660,6 +660,14 @@ Handle<Object> Factory::NewNumberFromUint(uint32_t value,
}


Handle<HeapNumber> Factory::NewHeapNumber(double value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateHeapNumber(value, pretenure), HeapNumber);
}


Handle<JSObject> Factory::NewNeanderObject() {
CALL_HEAP_FUNCTION(
isolate(),
@@ -1056,6 +1064,58 @@ Handle<JSArrayBuffer> Factory::NewJSArrayBuffer() {
}


Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
JSFunction* typed_array_fun;
Context* native_context = isolate()->context()->native_context();
switch (type) {
case kExternalUnsignedByteArray:
typed_array_fun = native_context->uint8_array_fun();
break;

case kExternalByteArray:
typed_array_fun = native_context->int8_array_fun();
break;

case kExternalUnsignedShortArray:
typed_array_fun = native_context->uint16_array_fun();
break;

case kExternalShortArray:
typed_array_fun = native_context->int16_array_fun();
break;

case kExternalUnsignedIntArray:
typed_array_fun = native_context->uint32_array_fun();
break;

case kExternalIntArray:
typed_array_fun = native_context->int32_array_fun();
break;

case kExternalFloatArray:
typed_array_fun = native_context->float_array_fun();
break;

case kExternalDoubleArray:
typed_array_fun = native_context->double_array_fun();
break;

case kExternalPixelArray:
typed_array_fun = native_context->uint8c_array_fun();
break;

default:
UNREACHABLE();
return Handle<JSTypedArray>();
}

CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(typed_array_fun),
JSTypedArray);
}


Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
CALL_HEAP_FUNCTION(
@@ -267,6 +267,9 @@ class Factory {
Handle<Object> NewNumberFromUint(uint32_t value,
PretenureFlag pretenure = NOT_TENURED);

Handle<HeapNumber> NewHeapNumber(double value,
PretenureFlag pretenure = NOT_TENURED);

// These objects are used by the api to create env-independent data
// structures in the heap.
Handle<JSObject> NewNeanderObject();
@@ -315,6 +318,8 @@ class Factory {

Handle<JSArrayBuffer> NewJSArrayBuffer();

Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type);

Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);

// Change the type of the argument into a JS object/function and reinitialize.
@@ -166,6 +166,9 @@ DEFINE_bool(harmony_observation, false,
"enable harmony object observation (implies harmony collections")
DEFINE_bool(harmony_typed_arrays, false,
"enable harmony typed arrays")
DEFINE_bool(harmony_array_buffer, false,
"enable harmony array buffer")
DEFINE_implication(harmony_typed_arrays, harmony_array_buffer)
DEFINE_bool(harmony_generators, false, "enable harmony generators")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
@@ -177,7 +180,7 @@ DEFINE_implication(harmony, harmony_observation)
DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
DEFINE_implication(harmony, harmony_typed_arrays)
// TODO[dslomov] add harmony => harmony_typed_arrays

// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
@@ -190,6 +193,9 @@ DEFINE_bool(clever_optimizations,
true,
"Optimize object size, Array shift, DOM strings and string +")
DEFINE_bool(pretenure_literals, true, "allocate literals in old space")
DEFINE_bool(track_fields, false, "track fields with only smi values")
DEFINE_bool(track_double_fields, false, "track fields with double values")
DEFINE_implication(track_double_fields, track_fields)

// Flags for data representation optimizations
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
@@ -225,6 +231,8 @@ DEFINE_bool(trace_gvn, false, "trace global value numbering")
DEFINE_bool(trace_representation, false, "trace representation types")
DEFINE_bool(trace_track_allocation_sites, false,
"trace the tracking of allocation sites")
DEFINE_bool(trace_migration, false, "trace object migration")
DEFINE_bool(trace_generalization, false, "trace map generalization")
DEFINE_bool(stress_pointer_maps, false, "pointer map for every instruction")
DEFINE_bool(stress_environments, false, "environment for every instruction")
DEFINE_int(deopt_every_n_times,
@@ -98,6 +98,12 @@ inline StackHandler::Kind StackHandler::kind() const {
}


inline unsigned StackHandler::index() const {
const int offset = StackHandlerConstants::kStateOffset;
return IndexField::decode(Memory::unsigned_at(address() + offset));
}


inline Object** StackHandler::context_address() const {
const int offset = StackHandlerConstants::kContextOffset;
return reinterpret_cast<Object**>(address() + offset);
@@ -213,6 +219,34 @@ Object* JavaScriptFrame::GetParameter(int index) const {
}


inline Address JavaScriptFrame::GetOperandSlot(int index) const {
Address base = fp() + JavaScriptFrameConstants::kLocal0Offset;
ASSERT(IsAddressAligned(base, kPointerSize));
ASSERT_EQ(type(), JAVA_SCRIPT);
ASSERT_LT(index, ComputeOperandsCount());
ASSERT_LE(0, index);
// Operand stack grows down.
return base - index * kPointerSize;
}


inline Object* JavaScriptFrame::GetOperand(int index) const {
return Memory::Object_at(GetOperandSlot(index));
}


inline int JavaScriptFrame::ComputeOperandsCount() const {
Address base = fp() + JavaScriptFrameConstants::kLocal0Offset;
// Base points to low address of first operand and stack grows down, so add
// kPointerSize to get the actual stack size.
intptr_t stack_size_in_bytes = (base + kPointerSize) - sp();
ASSERT(IsAligned(stack_size_in_bytes, kPointerSize));
ASSERT(type() == JAVA_SCRIPT);
ASSERT(stack_size_in_bytes >= 0);
return static_cast<int>(stack_size_in_bytes >> kPointerSizeLog2);
}


inline Object* JavaScriptFrame::receiver() const {
return GetParameter(-1);
}
@@ -840,6 +840,72 @@ void JavaScriptFrame::PrintTop(Isolate* isolate,
}


void JavaScriptFrame::SaveOperandStack(FixedArray* store,
int* stack_handler_index) const {
int operands_count = store->length();
ASSERT_LE(operands_count, ComputeOperandsCount());

// Visit the stack in LIFO order, saving operands and stack handlers into the
// array. The saved stack handlers store a link to the next stack handler,
// which will allow RestoreOperandStack to rewind the handlers.
StackHandlerIterator it(this, top_handler());
int i = operands_count - 1;
*stack_handler_index = -1;
for (; !it.done(); it.Advance()) {
StackHandler* handler = it.handler();
// Save operands pushed after the handler was pushed.
for (; GetOperandSlot(i) < handler->address(); i--) {
store->set(i, GetOperand(i));
}
ASSERT_GE(i + 1, StackHandlerConstants::kSlotCount);
ASSERT_EQ(handler->address(), GetOperandSlot(i));
int next_stack_handler_index = i + 1 - StackHandlerConstants::kSlotCount;
handler->Unwind(isolate(), store, next_stack_handler_index,
*stack_handler_index);
*stack_handler_index = next_stack_handler_index;
i -= StackHandlerConstants::kSlotCount;
}

// Save any remaining operands.
for (; i >= 0; i--) {
store->set(i, GetOperand(i));
}
}


void JavaScriptFrame::RestoreOperandStack(FixedArray* store,
int stack_handler_index) {
int operands_count = store->length();
ASSERT_LE(operands_count, ComputeOperandsCount());
int i = 0;
while (i <= stack_handler_index) {
if (i < stack_handler_index) {
// An operand.
ASSERT_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
Memory::Object_at(GetOperandSlot(i)) = store->get(i);
i++;
} else {
// A stack handler.
ASSERT_EQ(i, stack_handler_index);
// The FixedArray store grows up. The stack grows down. So the operand
// slot for i actually points to the bottom of the top word in the
// handler. The base of the StackHandler* is the address of the bottom
// word, which will be the last slot that is in the handler.
int handler_slot_index = i + StackHandlerConstants::kSlotCount - 1;
StackHandler *handler =
StackHandler::FromAddress(GetOperandSlot(handler_slot_index));
stack_handler_index = handler->Rewind(isolate(), store, i, fp());
i += StackHandlerConstants::kSlotCount;
}
}

for (; i < operands_count; i++) {
ASSERT_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
Memory::Object_at(GetOperandSlot(i)) = store->get(i);
}
}


void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
@@ -1436,6 +1502,60 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
}


// -------------------------------------------------------------------------


void StackHandler::Unwind(Isolate* isolate,
FixedArray* array,
int offset,
int previous_handler_offset) const {
STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
ASSERT_LE(0, offset);
ASSERT_GE(array->length(), offset + 5);
// Unwinding a stack handler into an array chains it in the opposite
// direction, re-using the "next" slot as a "previous" link, so that stack
// handlers can be later re-wound in the correct order. Decode the "state"
// slot into "index" and "kind" and store them separately, using the fp slot.
array->set(offset, Smi::FromInt(previous_handler_offset)); // next
array->set(offset + 1, *code_address()); // code
array->set(offset + 2, Smi::FromInt(static_cast<int>(index()))); // state
array->set(offset + 3, *context_address()); // context
array->set(offset + 4, Smi::FromInt(static_cast<int>(kind()))); // fp

*isolate->handler_address() = next()->address();
}


int StackHandler::Rewind(Isolate* isolate,
FixedArray* array,
int offset,
Address fp) {
STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
ASSERT_LE(0, offset);
ASSERT_GE(array->length(), offset + 5);
Smi* prev_handler_offset = Smi::cast(array->get(offset));
Code* code = Code::cast(array->get(offset + 1));
Smi* smi_index = Smi::cast(array->get(offset + 2));
Object* context = array->get(offset + 3);
Smi* smi_kind = Smi::cast(array->get(offset + 4));

unsigned state = KindField::encode(static_cast<Kind>(smi_kind->value())) |
IndexField::encode(static_cast<unsigned>(smi_index->value()));

Memory::Address_at(address() + StackHandlerConstants::kNextOffset) =
*isolate->handler_address();
Memory::Object_at(address() + StackHandlerConstants::kCodeOffset) = code;
Memory::uintptr_at(address() + StackHandlerConstants::kStateOffset) = state;
Memory::Object_at(address() + StackHandlerConstants::kContextOffset) =
context;
Memory::Address_at(address() + StackHandlerConstants::kFPOffset) = fp;

*isolate->handler_address() = address();

return prev_handler_offset->value();
}


// -------------------------------------------------------------------------

int NumRegs(RegList reglist) {
@@ -93,6 +93,7 @@ class StackHandlerConstants : public AllStatic {
static const int kFPOffset = 4 * kPointerSize;

static const int kSize = kFPOffset + kPointerSize;
static const int kSlotCount = kSize >> kPointerSizeLog2;
};


@@ -131,9 +132,15 @@ class StackHandler BASE_EMBEDDED {
inline bool is_catch() const;
inline bool is_finally() const;

// Generator support to preserve stack handlers.
void Unwind(Isolate* isolate, FixedArray* array, int offset,
int previous_handler_offset) const;
int Rewind(Isolate* isolate, FixedArray* array, int offset, Address fp);

private:
// Accessors.
inline Kind kind() const;
inline unsigned index() const;

inline Object** context_address() const;
inline Object** code_address() const;
@@ -536,6 +543,15 @@ class JavaScriptFrame: public StandardFrame {
return GetNumberOfIncomingArguments();
}

// Access the operand stack.
inline Address GetOperandSlot(int index) const;
inline Object* GetOperand(int index) const;
inline int ComputeOperandsCount() const;

// Generator support to preserve operand stack and stack handlers.
void SaveOperandStack(FixedArray* store, int* stack_handler_index) const;
void RestoreOperandStack(FixedArray* store, int stack_handler_index);

// Debugger access.
void SetParameterValue(int index, Object* value) const;

@@ -410,6 +410,11 @@ class FullCodeGenerator: public AstVisitor {
// this has to be a separate pass _before_ populating or executing any module.
void AllocateModules(ZoneList<Declaration*>* declarations);

// Generator code to return a fresh iterator result object. The "value"
// property is set to a value popped from the stack, and "done" is set
// according to the argument.
void EmitReturnIteratorResult(bool done);

// Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations
// has been matched and all code generated; false otherwise.
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// TODO(dcarney): remove
#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT

#include "v8.h"

#include "api.h"
@@ -232,7 +235,7 @@ class GlobalHandles::Node {

void MakeWeak(GlobalHandles* global_handles,
void* parameter,
WeakReferenceCallback weak_reference_callback,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback) {
ASSERT(state() != FREE);
set_state(WEAK);
@@ -264,7 +267,7 @@ class GlobalHandles::Node {
set_state(NEAR_DEATH);
set_parameter(NULL);

v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
v8::Persistent<v8::Value> object = ToApi<v8::Value>(handle());
{
// Check that we are not passing a finalized external string to
// the callback.
@@ -276,9 +279,11 @@ class GlobalHandles::Node {
VMState<EXTERNAL> state(isolate);
if (near_death_callback_ != NULL) {
if (IsWeakCallback::decode(flags_)) {
WeakReferenceCallback callback =
reinterpret_cast<WeakReferenceCallback>(near_death_callback_);
callback(object, par);
RevivableCallback callback =
reinterpret_cast<RevivableCallback>(near_death_callback_);
callback(reinterpret_cast<v8::Isolate*>(isolate),
&object,
par);
} else {
near_death_callback_(reinterpret_cast<v8::Isolate*>(isolate),
object,
@@ -490,9 +495,9 @@ void GlobalHandles::Destroy(Object** location) {

void GlobalHandles::MakeWeak(Object** location,
void* parameter,
WeakReferenceCallback weak_reference_callback,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback) {
ASSERT(near_death_callback != NULL);
ASSERT((weak_reference_callback == NULL) != (near_death_callback == NULL));
Node::FromLocation(location)->MakeWeak(this,
parameter,
weak_reference_callback,
@@ -130,6 +130,8 @@ class GlobalHandles {
// Destroy a global handle.
void Destroy(Object** location);

typedef WeakReferenceCallbacks<v8::Value, void>::Revivable RevivableCallback;

// Make the global handle weak and set the callback parameter for the
// handle. When the garbage collector recognizes that only weak global
// handles point to an object the handles are cleared and the callback
@@ -138,7 +140,7 @@ class GlobalHandles {
// reason is that Smi::FromInt(0) does not change during garage collection.
void MakeWeak(Object** location,
void* parameter,
WeakReferenceCallback weak_reference_callback,
RevivableCallback weak_reference_callback,
NearDeathCallback near_death_callback);

void RecordStats(HeapStats* stats);
@@ -53,8 +53,9 @@ Handle<T>::Handle(T* obj, Isolate* isolate) {

template <typename T>
inline bool Handle<T>::is_identical_to(const Handle<T> other) const {
ASSERT(location_ == NULL ||
reinterpret_cast<Address>(*location_) != kZapValue);
ASSERT(location_ == NULL || !(*location_)->IsFailure());
if (location_ == other.location_) return true;
if (location_ == NULL || other.location_ == NULL) return false;
// Dereferencing deferred handles to check object equality is safe.
SLOW_ASSERT(IsDereferenceAllowed(true) && other.IsDereferenceAllowed(true));
return *location_ == *other.location_;
@@ -63,24 +64,22 @@ inline bool Handle<T>::is_identical_to(const Handle<T> other) const {

template <typename T>
inline T* Handle<T>::operator*() const {
ASSERT(location_ != NULL);
ASSERT(reinterpret_cast<Address>(*location_) != kHandleZapValue);
ASSERT(location_ != NULL && !(*location_)->IsFailure());
SLOW_ASSERT(IsDereferenceAllowed(false));
return *BitCast<T**>(location_);
}

template <typename T>
inline T** Handle<T>::location() const {
ASSERT(location_ == NULL ||
reinterpret_cast<Address>(*location_) != kZapValue);
SLOW_ASSERT(IsDereferenceAllowed(false));
ASSERT(location_ == NULL || !(*location_)->IsFailure());
SLOW_ASSERT(location_ == NULL || IsDereferenceAllowed(false));
return location_;
}

#ifdef DEBUG
template <typename T>
bool Handle<T>::IsDereferenceAllowed(bool allow_deferred) const {
if (location_ == NULL) return true;
ASSERT(location_ != NULL);
Object* object = *BitCast<T**>(location_);
if (object->IsSmi()) return true;
HeapObject* heap_object = HeapObject::cast(object);
@@ -650,6 +650,10 @@ inline bool Heap::allow_allocation(bool new_state) {
return old;
}

inline void Heap::set_allow_allocation(bool allocation_allowed) {
allocation_allowed_ = allocation_allowed;
}

#endif


@@ -864,33 +868,41 @@ DisallowAllocationFailure::~DisallowAllocationFailure() {


#ifdef DEBUG
AssertNoAllocation::AssertNoAllocation() {
Isolate* isolate = ISOLATE;
active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
if (active_) {
old_state_ = isolate->heap()->allow_allocation(false);
bool EnterAllocationScope(Isolate* isolate, bool allow_allocation) {
bool active = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
bool last_state = isolate->heap()->IsAllocationAllowed();
if (active) {
// TODO(yangguo): Make HandleDereferenceGuard avoid isolate mutation in the
// same way if running on the optimizer thread.
isolate->heap()->set_allow_allocation(allow_allocation);
}
return last_state;
}


AssertNoAllocation::~AssertNoAllocation() {
if (active_) HEAP->allow_allocation(old_state_);
void ExitAllocationScope(Isolate* isolate, bool last_state) {
bool active = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
if (active) {
isolate->heap()->set_allow_allocation(last_state);
}
}


DisableAssertNoAllocation::DisableAssertNoAllocation() {
Isolate* isolate = ISOLATE;
active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
if (active_) {
old_state_ = isolate->heap()->allow_allocation(true);
}
AssertNoAllocation::AssertNoAllocation()
: last_state_(EnterAllocationScope(ISOLATE, false)) {
}

AssertNoAllocation::~AssertNoAllocation() {
ExitAllocationScope(ISOLATE, last_state_);
}

DisableAssertNoAllocation::~DisableAssertNoAllocation() {
if (active_) HEAP->allow_allocation(old_state_);
DisableAssertNoAllocation::DisableAssertNoAllocation()
: last_state_(EnterAllocationScope(ISOLATE, true)) {
}

DisableAssertNoAllocation::~DisableAssertNoAllocation() {
ExitAllocationScope(ISOLATE, last_state_);
}
#else

AssertNoAllocation::AssertNoAllocation() { }
@@ -1309,8 +1309,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors();
int real_size = js_obj->map()->NumberOfOwnDescriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
if (descs->GetDetails(i).descriptor_index() > real_size) continue;
for (int i = 0; i < real_size; i++) {
switch (descs->GetType(i)) {
case FIELD: {
int index = descs->GetFieldIndex(i);
@@ -1332,7 +1331,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
js_obj->GetInObjectPropertyOffset(index));
}
} else {
Object* value = js_obj->FastPropertyAt(index);
Object* value = js_obj->RawFastPropertyAt(index);
if (k != heap_->hidden_string()) {
SetPropertyReference(js_obj, entry, k, value);
} else {
@@ -3176,7 +3176,8 @@ void Heap::SetNumberStringCache(Object* number, String* string) {


MaybeObject* Heap::NumberToString(Object* number,
bool check_number_string_cache) {
bool check_number_string_cache,
PretenureFlag pretenure) {
isolate_->counters()->number_to_string_runtime()->Increment();
if (check_number_string_cache) {
Object* cached = GetNumberStringCache(number);
@@ -3197,7 +3198,8 @@ MaybeObject* Heap::NumberToString(Object* number,
}

Object* js_string;
MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
MaybeObject* maybe_js_string =
AllocateStringFromOneByte(CStrVector(str), pretenure);
if (maybe_js_string->ToObject(&js_string)) {
SetNumberStringCache(number, String::cast(js_string));
}
@@ -4156,7 +4158,9 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
for (int i = 0; i < count; i++) {
String* name = fun->shared()->GetThisPropertyAssignmentName(i);
ASSERT(name->IsInternalizedString());
FieldDescriptor field(name, i, NONE, i + 1);
// TODO(verwaest): Since we cannot update the boilerplate's map yet,
// initialize to the worst case.
FieldDescriptor field(name, i, NONE, Representation::Tagged());
descriptors->Set(i, &field, witness);
}
descriptors->Sort();
@@ -4336,8 +4340,7 @@ MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
AllocationSiteMode mode = TRACK_ALLOCATION_SITE;
if (to_kind != initial_map->elements_kind()) {
MaybeObject* maybe_new_map = constructor->GetElementsTransitionMap(
isolate(), to_kind);
MaybeObject* maybe_new_map = initial_map->AsElementsKind(to_kind);
if (!maybe_new_map->To(&initial_map)) return maybe_new_map;
// Possibly alter the mode, since we found an updated elements kind
// in the type info cell.
@@ -4585,12 +4588,10 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
// The global object might be created from an object template with accessors.
// Fill these accessors into the dictionary.
DescriptorArray* descs = map->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d = PropertyDetails(details.attributes(),
CALLBACKS,
details.descriptor_index());
PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
Object* value = descs->GetCallbacksObject(i);
MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
if (!maybe_value->ToObject(&value)) return maybe_value;
@@ -1476,6 +1476,7 @@ class Heap {

#ifdef DEBUG
bool IsAllocationAllowed() { return allocation_allowed_; }
inline void set_allow_allocation(bool allocation_allowed);
inline bool allow_allocation(bool enable);

bool disallow_allocation_failure() {
@@ -1530,6 +1531,14 @@ class Heap {
return new_space_high_promotion_mode_active_;
}

inline PretenureFlag GetPretenureMode() {
return new_space_high_promotion_mode_active_ ? TENURED : NOT_TENURED;
}

inline Address* NewSpaceHighPromotionModeActiveAddress() {
return reinterpret_cast<Address*>(&new_space_high_promotion_mode_active_);
}

inline intptr_t PromotedTotalSize() {
return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize();
}
@@ -1608,7 +1617,8 @@ class Heap {
static bool RootCanBeWrittenAfterInitialization(RootListIndex root_index);

MUST_USE_RESULT MaybeObject* NumberToString(
Object* number, bool check_number_string_cache = true);
Object* number, bool check_number_string_cache = true,
PretenureFlag pretenure = NOT_TENURED);
MUST_USE_RESULT MaybeObject* Uint32ToString(
uint32_t value, bool check_number_string_cache = true);

@@ -1975,7 +1985,8 @@ class Heap {

// Indicates that the new space should be kept small due to high promotion
// rates caused by the mutator allocating a lot of long-lived objects.
bool new_space_high_promotion_mode_active_;
// TODO(hpayer): change to bool if no longer accessed from generated code
intptr_t new_space_high_promotion_mode_active_;

// Limit that triggers a global GC on the next (normally caused) GC. This
// is checked when we have already decided to do a GC to help determine
@@ -2691,15 +2702,21 @@ class DescriptorLookupCache {
// { AssertNoAllocation nogc;
// ...
// }

#ifdef DEBUG
inline bool EnterAllocationScope(Isolate* isolate, bool allow_allocation);
inline void ExitAllocationScope(Isolate* isolate, bool last_state);
#endif


class AssertNoAllocation {
public:
inline AssertNoAllocation();
inline ~AssertNoAllocation();

#ifdef DEBUG
private:
bool old_state_;
bool active_;
bool last_state_;
#endif
};

@@ -2711,8 +2728,7 @@ class DisableAssertNoAllocation {

#ifdef DEBUG
private:
bool old_state_;
bool active_;
bool last_state_;
#endif
};

@@ -54,20 +54,6 @@ HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE


const char* Representation::Mnemonic() const {
switch (kind_) {
case kNone: return "v";
case kTagged: return "t";
case kDouble: return "d";
case kInteger32: return "i";
case kExternal: return "x";
default:
UNREACHABLE();
return NULL;
}
}


int HValue::LoopWeight() const {
const int w = FLAG_loop_weight;
static const int weights[] = { 1, w, w*w, w*w*w, w*w*w*w };
@@ -1615,15 +1601,6 @@ void HCheckMaps::SetSideEffectDominator(GVNFlag side_effect,
}


void HLoadElements::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
if (HasTypeCheck()) {
stream->Add(" ");
typecheck()->PrintNameTo(stream);
}
}


void HCheckMaps::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
stream->Add(" [%p", *map_set()->first());
@@ -1972,6 +1949,10 @@ void HPhi::DeleteFromGraph() {
void HPhi::InitRealUses(int phi_id) {
// Initialize real uses.
phi_id_ = phi_id;
// Compute a conservative approximation of truncating uses before inferring
// representations. The proper, exact computation will be done later, when
// inserting representation changes.
SetFlag(kTruncatingToInt32);
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* value = it.value();
if (!value->IsPhi()) {
@@ -1981,6 +1962,9 @@ void HPhi::InitRealUses(int phi_id) {
PrintF("#%d Phi is used by real #%d %s as %s\n",
id(), value->id(), value->Mnemonic(), rep.Mnemonic());
}
if (!value->IsSimulate() && !value->CheckFlag(kTruncatingToInt32)) {
ClearFlag(kTruncatingToInt32);
}
}
}
}
@@ -2076,7 +2060,12 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(false),
is_not_in_new_space_(true),
boolean_value_(handle->BooleanValue()) {
if (handle_->IsHeapObject()) {
Heap* heap = Handle<HeapObject>::cast(handle)->GetHeap();
is_not_in_new_space_ = !heap->InNewSpace(*handle);
}
if (handle_->IsNumber()) {
double n = handle_->Number();
has_int32_value_ = IsInteger32(n);
@@ -2105,12 +2094,14 @@ HConstant::HConstant(Handle<Object> handle,
Representation r,
HType type,
bool is_internalize_string,
bool is_not_in_new_space,
bool boolean_value)
: handle_(handle),
unique_id_(unique_id),
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(is_internalize_string),
is_not_in_new_space_(is_not_in_new_space),
boolean_value_(boolean_value),
type_from_value_(type) {
ASSERT(!handle.is_null());
@@ -2122,12 +2113,14 @@ HConstant::HConstant(Handle<Object> handle,

HConstant::HConstant(int32_t integer_value,
Representation r,
bool is_not_in_new_space,
Handle<Object> optional_handle)
: handle_(optional_handle),
unique_id_(),
has_int32_value_(true),
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
boolean_value_(integer_value != 0),
int32_value_(integer_value),
double_value_(FastI2D(integer_value)) {
@@ -2137,12 +2130,14 @@ HConstant::HConstant(int32_t integer_value,

HConstant::HConstant(double double_value,
Representation r,
bool is_not_in_new_space,
Handle<Object> optional_handle)
: handle_(optional_handle),
unique_id_(),
has_int32_value_(IsInteger32(double_value)),
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
boolean_value_(double_value != 0 && !std::isnan(double_value)),
int32_value_(DoubleToInt32(double_value)),
double_value_(double_value) {
@@ -2162,26 +2157,35 @@ void HConstant::Initialize(Representation r) {
HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
if (r.IsInteger32() && !has_int32_value_) return NULL;
if (r.IsDouble() && !has_double_value_) return NULL;
if (has_int32_value_) return new(zone) HConstant(int32_value_, r, handle_);
if (has_double_value_) return new(zone) HConstant(double_value_, r, handle_);
if (has_int32_value_) {
return new(zone) HConstant(int32_value_, r, is_not_in_new_space_, handle_);
}
if (has_double_value_) {
return new(zone) HConstant(double_value_, r, is_not_in_new_space_, handle_);
}
ASSERT(!handle_.is_null());
return new(zone) HConstant(handle_,
unique_id_,
r,
type_from_value_,
is_internalized_string_,
is_not_in_new_space_,
boolean_value_);
}


HConstant* HConstant::CopyToTruncatedInt32(Zone* zone) const {
if (has_int32_value_) {
return new(zone) HConstant(
int32_value_, Representation::Integer32(), handle_);
return new(zone) HConstant(int32_value_,
Representation::Integer32(),
is_not_in_new_space_,
handle_);
}
if (has_double_value_) {
return new(zone) HConstant(
DoubleToInt32(double_value_), Representation::Integer32(), handle_);
return new(zone) HConstant(DoubleToInt32(double_value_),
Representation::Integer32(),
is_not_in_new_space_,
handle_);
}
return NULL;
}
@@ -2517,6 +2521,8 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
i < types->length() && types_.length() < kMaxLoadPolymorphism;
++i) {
Handle<Map> map = types->at(i);
// Deprecated maps are updated to the current map in the type oracle.
ASSERT(!map->is_deprecated());
LookupResult lookup(map->GetIsolate());
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsFound()) {
@@ -2528,6 +2534,12 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
} else {
SetGVNFlag(kDependsOnBackingStoreFields);
}
if (FLAG_track_double_fields &&
lookup.representation().IsDouble()) {
// Since the value needs to be boxed, use a generic handler for
// loading doubles.
continue;
}
types_.Add(types->at(i), zone);
break;
}
@@ -3501,14 +3513,7 @@ void HPhi::SimplifyConstantInputs() {

void HPhi::InferRepresentation(HInferRepresentation* h_infer) {
ASSERT(CheckFlag(kFlexibleRepresentation));
// If there are non-Phi uses, and all of them have observed the same
// representation, than that's what this Phi is going to use.
Representation new_rep = RepresentationObservedByAllNonPhiUses();
if (!new_rep.IsNone()) {
UpdateRepresentation(new_rep, h_infer, "unanimous use observations");
return;
}
new_rep = RepresentationFromInputs();
Representation new_rep = RepresentationFromInputs();
UpdateRepresentation(new_rep, h_infer, "inputs");
new_rep = RepresentationFromUses();
UpdateRepresentation(new_rep, h_infer, "uses");
@@ -3517,22 +3522,6 @@ void HPhi::InferRepresentation(HInferRepresentation* h_infer) {
}


Representation HPhi::RepresentationObservedByAllNonPhiUses() {
int non_phi_use_count = 0;
for (int i = Representation::kInteger32;
i < Representation::kNumRepresentations; ++i) {
non_phi_use_count += non_phi_uses_[i];
}
if (non_phi_use_count <= 1) return Representation::None();
for (int i = 0; i < Representation::kNumRepresentations; ++i) {
if (non_phi_uses_[i] == non_phi_use_count) {
return Representation::FromKind(static_cast<Representation::Kind>(i));
}
}
return Representation::None();
}


Representation HPhi::RepresentationFromInputs() {
bool double_occurred = false;
bool int32_occurred = false;

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -982,6 +982,11 @@ class HGraphBuilder {
HValue* BuildCheckMap(HValue* obj, Handle<Map> map);

// Building common constructs
HLoadNamedField* DoBuildLoadNamedField(HValue* object,
bool inobject,
Representation representation,
int offset);

HInstruction* BuildExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
@@ -1025,6 +1030,8 @@ class HGraphBuilder {
HInstruction* BuildStoreMap(HValue* object, HValue* map);
HInstruction* BuildStoreMap(HValue* object, Handle<Map> map);

HLoadNamedField* AddLoadElements(HValue *object, HValue *typecheck = NULL);

class IfBuilder {
public:
explicit IfBuilder(HGraphBuilder* builder,
@@ -1317,6 +1324,9 @@ class HGraphBuilder {
int previous_object_size,
HValue* payload);

HInstruction* BuildGetNativeContext(HValue* context);
HInstruction* BuildGetArrayFunction(HValue* context);

private:
HGraphBuilder();
CompilationInfo* info_;
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_IA32)

#include "bootstrapper.h"
#include "builtins-decls.h"
#include "code-stubs.h"
#include "isolate.h"
#include "jsregexp.h"
@@ -79,6 +80,28 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
}


void LoadFieldStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { edx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}


void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { edx };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ = NULL;
}


void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -107,9 +130,10 @@ static void InitializeArrayConstructorDescriptor(
int constant_stack_parameter_count) {
// register state
// eax -- number of arguments
// edi -- function
// ebx -- type info cell with elements kind
static Register registers[] = { ebx };
descriptor->register_param_count_ = 1;
static Register registers[] = { edi, ebx };
descriptor->register_param_count_ = 2;

if (constant_stack_parameter_count != 0) {
// stack param count needs (constructor pointer, and single argument)
@@ -3298,12 +3322,6 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
}


void LoadFieldStub::Generate(MacroAssembler* masm) {
StubCompiler::DoGenerateFastPropertyLoad(masm, eax, reg_, inobject_, index_);
__ ret(0);
}


void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in edx and the parameter count is in eax.

@@ -4758,6 +4776,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
Handle<Object> terminal_kind_sentinel =
TypeFeedbackCells::MonomorphicArraySentinel(isolate,
LAST_FAST_ELEMENTS_KIND);
__ JumpIfNotSmi(ecx, &miss);
__ cmp(ecx, Immediate(terminal_kind_sentinel));
__ j(above, &miss);
// Load the global or builtins object from the current context
@@ -5821,8 +5840,33 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
__ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
Immediate(String::kEmptyHashField));

Label skip_write_barrier, after_writing;
ExternalReference high_promotion_mode = ExternalReference::
new_space_high_promotion_mode_active_address(masm->isolate());
__ test(Operand::StaticVariable(high_promotion_mode), Immediate(1));
__ j(zero, &skip_write_barrier);

__ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
__ RecordWriteField(ecx,
ConsString::kFirstOffset,
eax,
ebx,
kDontSaveFPRegs);
__ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
__ RecordWriteField(ecx,
ConsString::kSecondOffset,
edx,
ebx,
kDontSaveFPRegs);
__ jmp(&after_writing);

__ bind(&skip_write_barrier);
__ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
__ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);

__ bind(&after_writing);

__ mov(eax, ecx);
__ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
@@ -7354,8 +7398,10 @@ static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
{ REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET},
// StoreArrayLiteralElementStub::Generate
{ REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET},
// FastNewClosureStub
// FastNewClosureStub and StringAddStub::Generate
{ REG(ecx), REG(edx), REG(ebx), EMIT_REMEMBERED_SET},
// StringAddStub::Generate
{ REG(ecx), REG(eax), REG(ebx), EMIT_REMEMBERED_SET},
// Null termination.
{ REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
};
@@ -7876,15 +7922,8 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// Get the elements kind and case on that.
__ cmp(ebx, Immediate(undefined_sentinel));
__ j(equal, &no_info);
__ mov(edx, FieldOperand(ebx, kPointerSize));

// There is no info if the call site went megamorphic either

// TODO(mvstanton): Really? I thought if it was the array function that
// the cell wouldn't get stamped as megamorphic.
__ cmp(edx, Immediate(TypeFeedbackCells::MegamorphicSentinel(
masm->isolate())));
__ j(equal, &no_info);
__ mov(edx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
__ JumpIfNotSmi(edx, &no_info);
__ SmiUntag(edx);
__ jmp(&switch_ready);
__ bind(&no_info);
@@ -240,6 +240,15 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
}


void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
// Register state for CompareNil IC
// ----------- S t a t e -------------
// -- eax : value
// -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit(), 0, false);
}


void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
// Register state for keyed IC call call (from ic-ia32.cc)
// ----------- S t a t e -------------
@@ -1529,7 +1529,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
int properties_count = constant_properties->length() / 2;
if (expr->depth() > 1) {
if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
expr->depth() > 1) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
@@ -1900,11 +1901,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
Label resume;
__ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex);
__ j(not_equal, &resume);
__ pop(result_register());
if (expr->yield_kind() == Yield::SUSPEND) {
// TODO(wingo): Box into { value: VALUE, done: false }.
EmitReturnIteratorResult(false);
} else {
__ pop(result_register());
EmitReturnSequence();
}
EmitReturnSequence();

__ bind(&resume);
context()->Plug(result_register());
@@ -1916,18 +1918,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
__ mov(FieldOperand(result_register(),
JSGeneratorObject::kContinuationOffset),
Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
__ pop(result_register());
// TODO(wingo): Box into { value: VALUE, done: true }.

// Exit all nested statements.
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
int context_length = 0;
while (current != NULL) {
current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
EmitReturnSequence();
EmitReturnIteratorResult(true);
break;
}

@@ -2033,6 +2024,54 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
}


void FullCodeGenerator::EmitReturnIteratorResult(bool done) {
Label gc_required;
Label allocated;

Handle<Map> map(isolate()->native_context()->generator_result_map());

__ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT);

__ bind(&allocated);
__ mov(ebx, map);
__ pop(ecx);
__ mov(edx, isolate()->factory()->ToBoolean(done));
ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSObject::kElementsOffset),
isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
__ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);

// Only the value field needs a write barrier, as the other values are in the
// root set.
__ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
ecx, edx, kDontSaveFPRegs);

if (done) {
// Exit all nested statements.
NestedStatement* current = nesting_stack_;
int stack_depth = 0;
int context_length = 0;
while (current != NULL) {
current = current->Exit(&stack_depth, &context_length);
}
__ Drop(stack_depth);
}

EmitReturnSequence();

__ bind(&gc_required);
__ Push(Smi::FromInt(map->instance_size()));
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
__ mov(context_register(),
Operand(ebp, StandardFrameConstants::kContextOffset));
__ jmp(&allocated);
}


void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
@@ -1530,6 +1530,26 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
}


void StoreIC::GenerateSlow(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------

__ pop(ebx);
__ push(edx);
__ push(ecx);
__ push(eax);
__ push(ebx); // return address

// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}


void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
@@ -113,6 +113,10 @@ void LCodeGen::FinishCode(Handle<Code> code) {
prototype_maps_.at(i)->AddDependentCode(
DependentCode::kPrototypeCheckGroup, code);
}
for (int i = 0 ; i < transition_maps_.length(); i++) {
transition_maps_.at(i)->AddDependentCode(
DependentCode::kTransitionGroup, code);
}
}


@@ -1230,7 +1234,7 @@ void LCodeGen::DoModI(LModI* instr) {
__ and_(dividend, divisor - 1);
__ bind(&done);
} else {
Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
Label done, remainder_eq_dividend, slow, both_positive;
Register left_reg = ToRegister(instr->left());
Register right_reg = ToRegister(instr->right());
Register result_reg = ToRegister(instr->result());
@@ -1266,23 +1270,10 @@ void LCodeGen::DoModI(LModI* instr) {
__ mov(scratch, right_reg);
__ sub(Operand(scratch), Immediate(1));
__ test(scratch, Operand(right_reg));
__ j(not_zero, &do_subtraction, Label::kNear);
__ j(not_zero, &slow, Label::kNear);
__ and_(left_reg, Operand(scratch));
__ jmp(&remainder_eq_dividend, Label::kNear);

__ bind(&do_subtraction);
const int kUnfolds = 3;
// Try a few subtractions of the dividend.
__ mov(scratch, left_reg);
for (int i = 0; i < kUnfolds; i++) {
// Reduce the dividend by the divisor.
__ sub(left_reg, Operand(right_reg));
// Check if the dividend is less than the divisor.
__ cmp(left_reg, Operand(right_reg));
__ j(less, &remainder_eq_dividend, Label::kNear);
}
__ mov(left_reg, scratch);

// Slow case, using idiv instruction.
__ bind(&slow);

@@ -1915,16 +1906,24 @@ void LCodeGen::DoThrow(LThrow* instr) {
void LCodeGen::DoAddI(LAddI* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
ASSERT(left->Equals(instr->result()));

if (right->IsConstantOperand()) {
__ add(ToOperand(left), ToInteger32Immediate(right));
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
if (right->IsConstantOperand()) {
int32_t offset = ToInteger32(LConstantOperand::cast(right));
__ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
} else {
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
__ lea(ToRegister(instr->result()), address);
}
} else {
__ add(ToRegister(left), ToOperand(right));
}

if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
if (right->IsConstantOperand()) {
__ add(ToOperand(left), ToInteger32Immediate(right));
} else {
__ add(ToRegister(left), ToOperand(right));
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
}
}
}

@@ -2956,13 +2955,27 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {


void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
int offset = instr->hydrogen()->offset();
Register object = ToRegister(instr->object());
if (FLAG_track_double_fields &&
instr->hydrogen()->representation().IsDouble()) {
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2);
XMMRegister result = ToDoubleRegister(instr->result());
__ movdbl(result, FieldOperand(object, offset));
} else {
PushX87DoubleOperand(FieldOperand(object, offset));
CurrentInstructionReturnsX87Result();
}
return;
}

Register result = ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
__ mov(result, FieldOperand(object, offset));
} else {
__ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
__ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
__ mov(result, FieldOperand(result, offset));
}
}

@@ -3146,41 +3159,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
}


void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->object());
__ mov(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
Label done, ok, fail;
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_array_map()));
__ j(equal, &done, Label::kNear);
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_cow_array_map()));
__ j(equal, &done, Label::kNear);
Register temp((result.is(eax)) ? ebx : eax);
__ push(temp);
__ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
__ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Map::kElementsKindMask);
__ shr(temp, Map::kElementsKindShift);
__ cmp(temp, GetInitialFastElementsKind());
__ j(less, &fail, Label::kNear);
__ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
__ j(less_equal, &ok, Label::kNear);
__ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less, &fail, Label::kNear);
__ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
__ bind(&ok);
__ pop(temp);
__ bind(&done);
}
}


void LCodeGen::DoLoadExternalArrayPointer(
LLoadExternalArrayPointer* instr) {
Register result = ToRegister(instr->result());
@@ -4213,8 +4191,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {

__ Set(eax, Immediate(instr->arity()));
__ mov(ebx, instr->hydrogen()->property_cell());
Object* cell_value = instr->hydrogen()->property_cell()->value();
ElementsKind kind = static_cast<ElementsKind>(Smi::cast(cell_value)->value());
ElementsKind kind = instr->hydrogen()->elements_kind();
if (instr->arity() == 0) {
ArrayNoArgumentConstructorStub stub(kind);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
@@ -4241,16 +4218,51 @@ void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {


void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Representation representation = instr->representation();

Register object = ToRegister(instr->object());

int offset = instr->offset();

if (!instr->transition().is_null()) {
Handle<Map> transition = instr->transition();

if (FLAG_track_fields && representation.IsSmi()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (!IsInteger32(operand_value)) {
DeoptimizeIf(no_condition, instr->environment());
}
} else {
Register value = ToRegister(instr->value());
__ SmiTag(value);
if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
DeoptimizeIf(overflow, instr->environment());
}
}
} else if (FLAG_track_double_fields && representation.IsDouble()) {
ASSERT(transition.is_null());
ASSERT(instr->is_in_object());
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2);
XMMRegister value = ToDoubleRegister(instr->value());
__ movdbl(FieldOperand(object, offset), value);
} else {
__ fstp_d(FieldOperand(object, offset));
}
return;
}

if (!transition.is_null()) {
if (transition->CanBeDeprecated()) {
transition_maps_.Add(transition, info()->zone());
}
if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
__ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
__ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
} else {
Register temp = ToRegister(instr->temp());
Register temp_map = ToRegister(instr->temp_map());
__ mov(temp_map, instr->transition());
__ mov(temp_map, transition);
__ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
// Update the write barrier for the map field.
__ RecordWriteField(object,
@@ -4286,6 +4298,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
__ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
} else {
Handle<Object> handle_value = ToHandle(operand_value);
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
__ mov(FieldOperand(write_register, offset), handle_value);
}
} else {
@@ -5459,6 +5472,8 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
} else {
mode = NUMBER_CANDIDATE_IS_SMI;
}
} else {
mode = NUMBER_CANDIDATE_IS_SMI;
}
}

@@ -6025,18 +6040,24 @@ void LCodeGen::DoAllocate(LAllocate* instr) {


void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
Register size = ToRegister(instr->size());
Register result = ToRegister(instr->result());

__ SmiTag(size);
PushSafepointRegistersScope scope(this);
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
if (!size.is(result)) {
__ StoreToSafepointRegisterSlot(result, size);
__ mov(result, Immediate(Smi::FromInt(0)));

PushSafepointRegistersScope scope(this);
if (instr->size()->IsRegister()) {
Register size = ToRegister(instr->size());
ASSERT(!size.is(result));
__ SmiTag(ToRegister(instr->size()));
__ push(size);
} else {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
__ push(Immediate(Smi::FromInt(size)));
}
__ push(size);

if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
CallRuntimeFromDeferred(
Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
@@ -6125,7 +6146,8 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
// Set up the parameters to the stub/runtime call and pick the right
// runtime function or stub to call.
int properties_count = instr->hydrogen()->constant_properties_length() / 2;
if (instr->hydrogen()->depth() > 1) {
if ((FLAG_track_double_fields && instr->hydrogen()->may_store_doubles()) ||
instr->hydrogen()->depth() > 1) {
__ PushHeapObject(literals);
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
__ push(Immediate(constant_properties));
@@ -59,6 +59,7 @@ class LCodeGen BASE_EMBEDDED {
jump_table_(4, info->zone()),
deoptimization_literals_(8, info->zone()),
prototype_maps_(0, info->zone()),
transition_maps_(0, info->zone()),
inlined_function_count_(0),
scope_(info->scope()),
status_(UNUSED),
@@ -415,6 +416,7 @@ class LCodeGen BASE_EMBEDDED {
ZoneList<JumpTableEntry> jump_table_;
ZoneList<Handle<Object> > deoptimization_literals_;
ZoneList<Handle<Map> > prototype_maps_;
ZoneList<Handle<Map> > transition_maps_;
int inlined_function_count_;
Scope* const scope_;
Status status_;