@@ -147,6 +147,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() {

AddSimulate(BailoutId::StubEntry());

NoObservableSideEffectsScope no_effects(this);

HValue* return_value = BuildCodeStub();

// We might have extra expressions to pop from the stack in addition to the
@@ -188,6 +190,70 @@ static Handle<Code> DoGenerateCode(Stub* stub) {
}


template <>
HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
Zone* zone = this->zone();
Factory* factory = isolate()->factory();
AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
int length = casted_stub()->length();

HInstruction* boilerplate =
AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
GetParameter(1),
NULL,
FAST_ELEMENTS));

CheckBuilder builder(this);
builder.CheckNotUndefined(boilerplate);

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

IfBuilder if_fixed_cow(this);
if_fixed_cow.BeginIfMapEquals(elements, factory->fixed_cow_array_map());
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
alloc_site_mode,
FAST_ELEMENTS,
0/*copy-on-write*/));
if_fixed_cow.BeginElse();

IfBuilder if_fixed(this);
if_fixed.BeginIfMapEquals(elements, factory->fixed_array_map());
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
alloc_site_mode,
FAST_ELEMENTS,
length));
if_fixed.BeginElse();

environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
alloc_site_mode,
FAST_DOUBLE_ELEMENTS,
length));
} else {
ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
alloc_site_mode,
elements_kind,
length));
}

return environment()->Pop();
}


Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
CodeStubGraphBuilder<FastCloneShallowArrayStub> builder(this);
LChunk* chunk = OptimizeGraph(builder.CreateGraph());
return chunk->Codegen(Code::COMPILED_STUB);
}


template <>
HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
Zone* zone = this->zone();
@@ -230,7 +296,6 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
factory->empty_string(),
value,
true, i));
AddSimulate(BailoutId::StubEntry());
}

builder.End();
@@ -264,7 +329,6 @@ HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
GetParameter(0), GetParameter(1), GetParameter(2), NULL,
casted_stub()->is_js_array(), casted_stub()->elements_kind(),
true, casted_stub()->store_mode(), Representation::Tagged());
AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE);

return GetParameter(2);
}
@@ -308,7 +372,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
AddInstruction(new(zone) HFixedArrayBaseLength(elements));

HValue* new_elements =
BuildAllocateElements(context(), to_kind, elements_length);
BuildAllocateAndInitializeElements(context(), to_kind, elements_length);

BuildCopyElements(context(), elements,
casted_stub()->from_kind(), new_elements,
@@ -320,13 +384,11 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
factory->elements_field_string(),
new_elements, true,
JSArray::kElementsOffset));
AddSimulate(BailoutId::StubEntry());

if_builder.End();

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

@@ -619,8 +619,10 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {


void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).GetCode(isolate);
StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).GetCode(isolate);
StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
stub1.GetCode(isolate)->set_is_pregenerated(true);
stub2.GetCode(isolate)->set_is_pregenerated(true);
}


@@ -393,17 +393,24 @@ class ToNumberStub: public PlatformCodeStub {

class FastNewClosureStub : public PlatformCodeStub {
public:
explicit FastNewClosureStub(LanguageMode language_mode)
: language_mode_(language_mode) { }
explicit FastNewClosureStub(LanguageMode language_mode, bool is_generator)
: language_mode_(language_mode),
is_generator_(is_generator) { }

void Generate(MacroAssembler* masm);

private:
class StrictModeBits: public BitField<bool, 0, 1> {};
class IsGeneratorBits: public BitField<bool, 1, 1> {};

Major MajorKey() { return FastNewClosure; }
int MinorKey() { return language_mode_ == CLASSIC_MODE
? kNonStrictMode : kStrictMode; }
int MinorKey() {
return StrictModeBits::encode(language_mode_ != CLASSIC_MODE) |
IsGeneratorBits::encode(is_generator_);
}

LanguageMode language_mode_;
bool is_generator_;
};


@@ -443,7 +450,7 @@ class FastNewBlockContextStub : public PlatformCodeStub {
};


class FastCloneShallowArrayStub : public PlatformCodeStub {
class FastCloneShallowArrayStub : public HydrogenCodeStub {
public:
// Maximum length of copied elements array.
static const int kMaximumClonedLength = 8;
@@ -467,7 +474,31 @@ class FastCloneShallowArrayStub : public PlatformCodeStub {
ASSERT_LE(length_, kMaximumClonedLength);
}

void Generate(MacroAssembler* masm);
Mode mode() const { return mode_; }
int length() const { return length_; }
AllocationSiteMode allocation_site_mode() const {
return allocation_site_mode_;
}

ElementsKind ComputeElementsKind() const {
switch (mode()) {
case CLONE_ELEMENTS:
case COPY_ON_WRITE_ELEMENTS:
return FAST_ELEMENTS;
case CLONE_DOUBLE_ELEMENTS:
return FAST_DOUBLE_ELEMENTS;
case CLONE_ANY_ELEMENTS:
/*fall-through*/;
}
UNREACHABLE();
return LAST_ELEMENTS_KIND;
}

virtual Handle<Code> GenerateCode();

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

private:
Mode mode_;
@@ -746,7 +777,7 @@ class BinaryOpStub: public PlatformCodeStub {
private:
Token::Value op_;
OverwriteMode mode_;
bool platform_specific_bit_; // Indicates SSE3 on IA32, VFP2 on ARM.
bool platform_specific_bit_; // Indicates SSE3 on IA32.

// Operand type information determined at runtime.
BinaryOpIC::TypeInfo left_type_;
@@ -1604,18 +1635,25 @@ class StoreArrayLiteralElementStub : public PlatformCodeStub {
class StubFailureTrampolineStub : public PlatformCodeStub {
public:
explicit StubFailureTrampolineStub(StubFunctionMode function_mode)
: function_mode_(function_mode) {}
: fp_registers_(CanUseFPRegisters()), function_mode_(function_mode) {}

virtual bool IsPregenerated() { return true; }

static void GenerateAheadOfTime(Isolate* isolate);

private:
class FPRegisters: public BitField<bool, 0, 1> {};
class FunctionModeField: public BitField<StubFunctionMode, 1, 1> {};

Major MajorKey() { return StubFailureTrampoline; }
int MinorKey() { return static_cast<int>(function_mode_); }
int MinorKey() {
return FPRegisters::encode(fp_registers_) |
FunctionModeField::encode(function_mode_);
}

void Generate(MacroAssembler* masm);

bool fp_registers_;
StubFunctionMode function_mode_;

DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub);
@@ -27,16 +27,20 @@

"use strict";

// This file relies on the fact that the following declaration has been made
// in runtime.js:
// var $Array = global.Array;

var $Set = global.Set;
var $Map = global.Map;
var $WeakMap = global.WeakMap;

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

// Global sentinel to be used instead of undefined keys, which are not
// supported internally but required for Harmony sets and maps.
var undefined_sentinel = {};

// -------------------------------------------------------------------
// Harmony Set

function SetConstructor() {
if (%_IsConstructCall()) {
@@ -107,6 +111,31 @@ function SetClear() {
}


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

function SetUpSet() {
%CheckIsBootstrapping();

%SetCode($Set, SetConstructor);
%FunctionSetPrototype($Set, new $Object());
%SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);

// Set up the non-enumerable functions on the Set prototype object.
InstallGetter($Set.prototype, "size", SetGetSize);
InstallFunctions($Set.prototype, DONT_ENUM, $Array(
"add", SetAdd,
"has", SetHas,
"delete", SetDelete,
"clear", SetClear
));
}

SetUpSet();


// -------------------------------------------------------------------
// Harmony Map

function MapConstructor() {
if (%_IsConstructCall()) {
%MapInitialize(this);
@@ -183,6 +212,32 @@ function MapClear() {
}


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

function SetUpMap() {
%CheckIsBootstrapping();

%SetCode($Map, MapConstructor);
%FunctionSetPrototype($Map, new $Object());
%SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);

// Set up the non-enumerable functions on the Map prototype object.
InstallGetter($Map.prototype, "size", MapGetSize);
InstallFunctions($Map.prototype, DONT_ENUM, $Array(
"get", MapGet,
"set", MapSet,
"has", MapHas,
"delete", MapDelete,
"clear", MapClear
));
}

SetUpMap();


// -------------------------------------------------------------------
// Harmony WeakMap

function WeakMapConstructor() {
if (%_IsConstructCall()) {
%WeakMapInitialize(this);
@@ -239,42 +294,14 @@ function WeakMapDelete(key) {
return %WeakMapDelete(this, key);
}


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

(function () {
function SetUpWeakMap() {
%CheckIsBootstrapping();

// Set up the Set and Map constructor function.
%SetCode($Set, SetConstructor);
%SetCode($Map, MapConstructor);

// Set up the constructor property on the Set and Map prototype object.
%SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
%SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);

// Set up the non-enumerable functions on the Set prototype object.
InstallGetter($Set.prototype, "size", SetGetSize);
InstallFunctions($Set.prototype, DONT_ENUM, $Array(
"add", SetAdd,
"has", SetHas,
"delete", SetDelete,
"clear", SetClear
));

// Set up the non-enumerable functions on the Map prototype object.
InstallGetter($Map.prototype, "size", MapGetSize);
InstallFunctions($Map.prototype, DONT_ENUM, $Array(
"get", MapGet,
"set", MapSet,
"has", MapHas,
"delete", MapDelete,
"clear", MapClear
));

// Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);

// Set up the constructor property on the WeakMap prototype object.
%FunctionSetPrototype($WeakMap, new $Object());
%SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);

// Set up the non-enumerable functions on the WeakMap prototype object.
@@ -284,4 +311,6 @@ function WeakMapDelete(key) {
"has", WeakMapHas,
"delete", WeakMapDelete
));
})();
}

SetUpWeakMap();
@@ -520,14 +520,15 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {

// Only allow non-global compiles for eval.
ASSERT(info->is_eval() || info->is_global());
ParsingFlags flags = kNoParsingFlags;
if ((info->pre_parse_data() != NULL ||
String::cast(script->source())->length() > FLAG_min_preparse_length) &&
!DebuggerWantsEagerCompilation(info)) {
flags = kAllowLazy;
}
if (!ParserApi::Parse(info, flags)) {
return Handle<SharedFunctionInfo>::null();
{
Parser parser(info);
if ((info->pre_parse_data() != NULL ||
String::cast(script->source())->length() > FLAG_min_preparse_length) &&
!DebuggerWantsEagerCompilation(info))
parser.set_allow_lazy(true);
if (!parser.Parse()) {
return Handle<SharedFunctionInfo>::null();
}
}

// Measure how long it takes to do the compilation; only take the
@@ -864,7 +865,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
if (InstallCodeFromOptimizedCodeMap(info)) return true;

// Generate the AST for the lazily compiled function.
if (ParserApi::Parse(info, kNoParsingFlags)) {
if (Parser::Parse(info)) {
// Measure how long it takes to do the lazy compilation; only take the
// rest of the function into account to avoid overlap with the lazy
// parsing statistics.
@@ -932,7 +933,7 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
return;
}

if (ParserApi::Parse(*info, kNoParsingFlags)) {
if (Parser::Parse(*info)) {
LanguageMode language_mode = info->function()->language_mode();
info->SetLanguageMode(language_mode);
shared->set_language_mode(language_mode);
@@ -957,18 +958,18 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
}
}

if (shared->code()->stack_check_patched_for_osr()) {
if (shared->code()->back_edges_patched_for_osr()) {
// At this point we either put the function on recompilation queue or
// aborted optimization. In either case we want to continue executing
// the unoptimized code without running into OSR. If the unoptimized
// code has been patched for OSR, unpatch it.
InterruptStub interrupt_stub;
Handle<Code> check_code = interrupt_stub.GetCode(isolate);
Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
Handle<Code> replacement_code =
isolate->builtins()->OnStackReplacement();
Deoptimizer::RevertStackCheckCode(shared->code(),
*check_code,
*replacement_code);
Deoptimizer::RevertInterruptCode(shared->code(),
*interrupt_code,
*replacement_code);
}

if (isolate->has_pending_exception()) isolate->clear_pending_exception();
@@ -165,6 +165,11 @@ enum BindingFlags {
V(PROXY_ENUMERATE_INDEX, JSFunction, proxy_enumerate) \
V(OBSERVERS_NOTIFY_CHANGE_INDEX, JSFunction, observers_notify_change) \
V(OBSERVERS_DELIVER_CHANGES_INDEX, JSFunction, observers_deliver_changes) \
V(GENERATOR_FUNCTION_MAP_INDEX, Map, generator_function_map) \
V(STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX, Map, \
strict_mode_generator_function_map) \
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
generator_object_prototype_map) \
V(RANDOM_SEED_INDEX, ByteArray, random_seed)

// JSFunctions are pairs (context, function code), sometimes also called
@@ -295,6 +300,9 @@ class Context: public FixedArray {
PROXY_ENUMERATE_INDEX,
OBSERVERS_NOTIFY_CHANGE_INDEX,
OBSERVERS_DELIVER_CHANGES_INDEX,
GENERATOR_FUNCTION_MAP_INDEX,
STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
RANDOM_SEED_INDEX,

// Properties from here are treated as weak references by the full GC.
@@ -439,6 +447,16 @@ class Context: public FixedArray {
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
}

static int FunctionMapIndex(LanguageMode language_mode, bool is_generator) {
return is_generator
? (language_mode == CLASSIC_MODE
? GENERATOR_FUNCTION_MAP_INDEX
: STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX)
: (language_mode == CLASSIC_MODE
? FUNCTION_MAP_INDEX
: STRICT_MODE_FUNCTION_MAP_INDEX);
}

static const int kSize = kHeaderSize + NATIVE_CONTEXT_SLOTS * kPointerSize;

// GC support.
@@ -77,7 +77,7 @@ inline unsigned int FastD2UI(double x) {
uint32_t result;
Address mantissa_ptr = reinterpret_cast<Address>(&x);
// Copy least significant 32 bits of mantissa.
memcpy(&result, mantissa_ptr, sizeof(result));
OS::MemCopy(&result, mantissa_ptr, sizeof(result));
return negative ? ~result + 1 : result;
}
// Large number (outside uint32 range), Infinity or NaN.
@@ -445,7 +445,7 @@ void CpuProfiler::StartProcessorIfNotStarted() {
generator_ = new ProfileGenerator(profiles_);
processor_ = new ProfilerEventsProcessor(generator_);
is_profiling_ = true;
processor_->Start();
processor_->StartSynchronously();
// Enumerate stuff we already have in the heap.
if (isolate_->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
@@ -459,11 +459,11 @@ void CpuProfiler::StartProcessorIfNotStarted() {
}
// Enable stack sampling.
Sampler* sampler = reinterpret_cast<Sampler*>(isolate_->logger()->ticker_);
sampler->IncreaseProfilingDepth();
if (!sampler->IsActive()) {
sampler->Start();
need_to_stop_sampler_ = true;
}
sampler->IncreaseProfilingDepth();
}
}

@@ -31,6 +31,7 @@
#include "allocation.h"
#include "atomicops.h"
#include "circular-queue.h"
#include "sampler.h"
#include "unbound-queue.h"

namespace v8 {
@@ -45,6 +45,10 @@
#include "../include/v8-testing.h"
#endif // V8_SHARED

#ifdef ENABLE_VTUNE_JIT_INTERFACE
#include "third_party/vtune/v8-vtune.h"
#endif

#include "d8.h"

#ifndef V8_SHARED
@@ -144,6 +148,11 @@ class DumbLineEditor: public LineEditor {

Handle<String> DumbLineEditor::Prompt(const char* prompt) {
printf("%s", prompt);
#if defined(__native_client__)
// Native Client libc is used to being embedded in Chrome and
// has trouble recognizing when to flush.
fflush(stdout);
#endif
return Shell::ReadFromStdin(isolate_);
}

@@ -1921,6 +1930,9 @@ int Shell::Main(int argc, char* argv[]) {
DumbLineEditor dumb_line_editor(isolate);
{
Initialize(isolate);
#ifdef ENABLE_VTUNE_JIT_INTERFACE
vTune::InitilizeVtuneForV8();
#endif
Symbols symbols(isolate);
InitializeDebugger(isolate);

@@ -29,6 +29,8 @@
'includes': ['../build/common.gypi'],
'variables': {
'console%': '',
# Enable support for Intel VTune. Supported on ia32/x64 only
'v8_enable_vtunejit%': 0,
},
'targets': [
{
@@ -70,6 +72,11 @@
}],
],
}],
['v8_enable_vtunejit==1', {
'dependencies': [
'../src/third_party/vtune/v8vtune.gyp:v8_vtune',
],
}],
],
},
{
@@ -25,20 +25,16 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


// This file relies on the fact that the following declarations have been made
// in v8natives.js:
// var $isFinite = GlobalIsFinite;

var $Date = global.Date;

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

// This file contains date support implemented in JavaScript.

// Keep reference to original values of some global properties. This
// has the added benefit that the code in this file is isolated from
// changes to these properties.
var $Date = global.Date;

// Helper function to throw error.
function ThrowDateTypeError() {
throw new $TypeError('this is not a Date object.');
@@ -142,7 +138,7 @@ var Date_cache = {
};


%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
if (!%_IsConstructCall()) {
// ECMA 262 - 15.9.2
return (new $Date()).toString();
@@ -199,10 +195,7 @@ var Date_cache = {
value = MakeDate(day, time);
SET_LOCAL_DATE_VALUE(this, value);
}
});


%FunctionSetPrototype($Date, new $Date($NaN));
}


var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -767,6 +760,10 @@ function ResetDateCache() {

function SetUpDate() {
%CheckIsBootstrapping();

%SetCode($Date, DateConstructor);
%FunctionSetPrototype($Date, new $Date($NaN));

// Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC,
@@ -551,9 +551,9 @@ void Debug::ThreadInit() {

char* Debug::ArchiveDebug(char* storage) {
char* to = storage;
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
to += sizeof(ThreadLocal);
memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
OS::MemCopy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
ThreadInit();
ASSERT(to <= storage + ArchiveSpacePerThread());
return storage + ArchiveSpacePerThread();
@@ -562,9 +562,10 @@ char* Debug::ArchiveDebug(char* storage) {

char* Debug::RestoreDebug(char* storage) {
char* from = storage;
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
OS::MemCopy(
reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
from += sizeof(ThreadLocal);
memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
OS::MemCopy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
ASSERT(from <= storage + ArchiveSpacePerThread());
return storage + ArchiveSpacePerThread();
}
@@ -874,8 +875,9 @@ bool Debug::Load() {
// Check for caught exceptions.
if (caught_exception) return false;

// Debugger loaded.
debug_context_ = context;
// Debugger loaded, create debugger context global handle.
debug_context_ = Handle<Context>::cast(
isolate_->global_handles()->Create(*context));

return true;
}
@@ -891,7 +893,7 @@ void Debug::Unload() {
DestroyScriptCache();

// Clear debugger context global handle.
Isolate::Current()->global_handles()->Destroy(
isolate_->global_handles()->Destroy(
reinterpret_cast<Object**>(debug_context_.location()));
debug_context_ = Handle<Context>();
}
@@ -1204,6 +1204,7 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
// and the standard stack frame slots. Include space for an argument
// object to the callee and optionally the space to pass the argument
// object to the stub failure handler.
ASSERT(descriptor->register_param_count_ >= 0);
int height_in_bytes = kPointerSize * descriptor->register_param_count_ +
sizeof(Arguments) + kPointerSize;
int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
@@ -2029,52 +2030,96 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
}


void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
Code* check_code,
Code* replacement_code) {
// Iterate over the stack check table and patch every stack check
void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code) {
// Iterate over the back edge table and patch every interrupt
// call to an unconditional call to the replacement code.
ASSERT(unoptimized_code->kind() == Code::FUNCTION);
ASSERT(!unoptimized_code->stack_check_patched_for_osr());
Address stack_check_cursor = unoptimized_code->instruction_start() +
unoptimized_code->stack_check_table_offset();
uint32_t table_length = Memory::uint32_at(stack_check_cursor);
stack_check_cursor += kIntSize;
int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
Address back_edge_cursor = unoptimized_code->instruction_start() +
unoptimized_code->back_edge_table_offset();
uint32_t table_length = Memory::uint32_at(back_edge_cursor);
back_edge_cursor += kIntSize;
for (uint32_t i = 0; i < table_length; ++i) {
uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
PatchStackCheckCodeAt(unoptimized_code,
pc_after,
check_code,
replacement_code);
stack_check_cursor += 2 * kIntSize;
uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
if (loop_depth == loop_nesting_level) {
// Loop back edge has the loop depth that we want to patch.
uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
PatchInterruptCodeAt(unoptimized_code,
pc_after,
interrupt_code,
replacement_code);
}
back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
unoptimized_code->set_stack_check_patched_for_osr(true);
unoptimized_code->set_back_edges_patched_for_osr(true);
#ifdef DEBUG
Deoptimizer::VerifyInterruptCode(
unoptimized_code, interrupt_code, replacement_code, loop_nesting_level);
#endif // DEBUG
}


void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
Code* check_code,
Code* replacement_code) {
// Iterate over the stack check table and revert the patched
// stack check calls.
void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code) {
// Iterate over the back edge table and revert the patched interrupt calls.
ASSERT(unoptimized_code->kind() == Code::FUNCTION);
ASSERT(unoptimized_code->stack_check_patched_for_osr());
Address stack_check_cursor = unoptimized_code->instruction_start() +
unoptimized_code->stack_check_table_offset();
uint32_t table_length = Memory::uint32_at(stack_check_cursor);
stack_check_cursor += kIntSize;
ASSERT(unoptimized_code->back_edges_patched_for_osr());
int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
Address back_edge_cursor = unoptimized_code->instruction_start() +
unoptimized_code->back_edge_table_offset();
uint32_t table_length = Memory::uint32_at(back_edge_cursor);
back_edge_cursor += kIntSize;
for (uint32_t i = 0; i < table_length; ++i) {
uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
if (loop_depth <= loop_nesting_level) {
uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
RevertInterruptCodeAt(unoptimized_code,
pc_after,
interrupt_code,
replacement_code);
}
back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
unoptimized_code->set_back_edges_patched_for_osr(false);
#ifdef DEBUG
// Assert that none of the back edges are patched anymore.
Deoptimizer::VerifyInterruptCode(
unoptimized_code, interrupt_code, replacement_code, -1);
#endif // DEBUG
}


#ifdef DEBUG
void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code,
int loop_nesting_level) {
CHECK(unoptimized_code->kind() == Code::FUNCTION);
Address back_edge_cursor = unoptimized_code->instruction_start() +
unoptimized_code->back_edge_table_offset();
uint32_t table_length = Memory::uint32_at(back_edge_cursor);
back_edge_cursor += kIntSize;
for (uint32_t i = 0; i < table_length; ++i) {
uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
CHECK_LE(loop_depth, Code::kMaxLoopNestingMarker);
// Assert that all back edges for shallower loops (and only those)
// have already been patched.
uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
RevertStackCheckCodeAt(unoptimized_code,
pc_after,
check_code,
replacement_code);
stack_check_cursor += 2 * kIntSize;
CHECK_EQ((loop_depth <= loop_nesting_level),
InterruptCodeIsPatched(unoptimized_code,
pc_after,
interrupt_code,
replacement_code));
back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
}
unoptimized_code->set_stack_check_patched_for_osr(false);
}
#endif // DEBUG


unsigned Deoptimizer::ComputeInputFrameSize() const {
@@ -2327,7 +2372,8 @@ int32_t TranslationIterator::Next() {
Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
int length = contents_.length();
Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
OS::MemCopy(
result->GetDataStartAddress(), contents_.ToVector().start(), length);
return result;
}

@@ -210,32 +210,45 @@ class Deoptimizer : public Malloced {
// The size in bytes of the code required at a lazy deopt patch site.
static int patch_size();

// Patch all stack guard checks in the unoptimized code to
// Patch all interrupts with allowed loop depth in the unoptimized code to
// unconditionally call replacement_code.
static void PatchStackCheckCode(Code* unoptimized_code,
Code* check_code,
Code* replacement_code);
static void PatchInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code);

// Patch stack guard check at instruction before pc_after in
// Patch the interrupt at the instruction before pc_after in
// the unoptimized code to unconditionally call replacement_code.
static void PatchStackCheckCodeAt(Code* unoptimized_code,
static void PatchInterruptCodeAt(Code* unoptimized_code,
Address pc_after,
Code* interrupt_code,
Code* replacement_code);

// Change all patched interrupts patched in the unoptimized code
// back to normal interrupts.
static void RevertInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code);

// Change patched interrupt in the unoptimized code
// back to a normal interrupt.
static void RevertInterruptCodeAt(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* interrupt_code,
Code* replacement_code);

// Change all patched stack guard checks in the unoptimized code
// back to a normal stack guard check.
static void RevertStackCheckCode(Code* unoptimized_code,
Code* check_code,
Code* replacement_code);

// Change all patched stack guard checks in the unoptimized code
// back to a normal stack guard check.
static void RevertStackCheckCodeAt(Code* unoptimized_code,
#ifdef DEBUG
static bool InterruptCodeIsPatched(Code* unoptimized_code,
Address pc_after,
Code* check_code,
Code* interrupt_code,
Code* replacement_code);

// Verify that all back edges of a certain loop depth are patched.
static void VerifyInterruptCode(Code* unoptimized_code,
Code* interrupt_code,
Code* replacement_code,
int loop_nesting_level);
#endif // DEBUG

~Deoptimizer();

void MaterializeHeapObjects(JavaScriptFrameIterator* it);
@@ -50,8 +50,8 @@ void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
pc - begin,
*pc);
} else {
fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
PrintF(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
}
}
}
@@ -101,13 +101,12 @@ static void DumpBuffer(FILE* f, StringBuilder* out) {
if (f == NULL) {
PrintF("%s\n", out->Finalize());
} else {
fprintf(f, "%s\n", out->Finalize());
PrintF(f, "%s\n", out->Finalize());
}
out->Reset();
}



static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57;

@@ -337,10 +336,10 @@ void Disassembler::Decode(FILE* f, Code* code) {
code->kind() == Code::COMPILED_STUB)
? static_cast<int>(code->safepoint_table_offset())
: code->instruction_size();
// If there might be a stack check table, stop before reaching it.
// If there might be a back edge table, stop before reaching it.
if (code->kind() == Code::FUNCTION) {
decode_size =
Min(decode_size, static_cast<int>(code->stack_check_table_offset()));
Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
}

byte* begin = code->instruction_start();
@@ -183,7 +183,7 @@ static void CopyObjectToObjectElements(FixedArrayBase* from_base,
Address from_address = from->address() + FixedArray::kHeaderSize;
CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
reinterpret_cast<Object**>(from_address) + from_start,
copy_size);
static_cast<size_t>(copy_size));
if (IsFastObjectElementsKind(from_kind) &&
IsFastObjectElementsKind(to_kind)) {
Heap* heap = from->GetHeap();
@@ -339,7 +339,7 @@ static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
int words_per_double = (kDoubleSize / kPointerSize);
CopyWords(reinterpret_cast<Object**>(to_address),
reinterpret_cast<Object**>(from_address),
words_per_double * copy_size);
static_cast<size_t>(words_per_double * copy_size));
}


@@ -33,6 +33,7 @@
#include "bootstrapper.h"
#include "codegen.h"
#include "debug.h"
#include "deoptimizer.h"
#include "isolate-inl.h"
#include "runtime-profiler.h"
#include "simulator.h"
@@ -448,6 +449,19 @@ void StackGuard::RequestGC() {
}


bool StackGuard::IsFullDeopt() {
ExecutionAccess access(isolate_);
return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
}


void StackGuard::FullDeopt() {
ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= FULL_DEOPT;
set_interrupt_limits(access);
}


#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
ExecutionAccess access(isolate_);
@@ -488,7 +502,7 @@ void StackGuard::Continue(InterruptFlag after_what) {

char* StackGuard::ArchiveStackGuard(char* to) {
ExecutionAccess access(isolate_);
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
ThreadLocal blank;

// Set the stack limits using the old thread_local_.
@@ -505,7 +519,8 @@ char* StackGuard::ArchiveStackGuard(char* to) {

char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access(isolate_);
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
OS::MemCopy(
reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
isolate_->heap()->SetStackLimits();
return from + sizeof(ThreadLocal);
}
@@ -880,7 +895,6 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
stack_guard->Continue(GC_REQUEST);
}


isolate->counters()->stack_interrupts()->Increment();
isolate->counters()->runtime_profiler_ticks()->Increment();
isolate->runtime_profiler()->OptimizeNow();
@@ -898,6 +912,10 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
stack_guard->Continue(INTERRUPT);
return isolate->StackOverflow();
}
if (stack_guard->IsFullDeopt()) {
stack_guard->Continue(FULL_DEOPT);
Deoptimizer::DeoptimizeAll(isolate);
}
return isolate->heap()->undefined_value();
}

@@ -41,7 +41,8 @@ enum InterruptFlag {
DEBUGCOMMAND = 1 << 2,
PREEMPT = 1 << 3,
TERMINATE = 1 << 4,
GC_REQUEST = 1 << 5
GC_REQUEST = 1 << 5,
FULL_DEOPT = 1 << 6
};


@@ -197,6 +198,8 @@ class StackGuard {
#endif
bool IsGCRequest();
void RequestGC();
bool IsFullDeopt();
void FullDeopt();
void Continue(InterruptFlag after_what);

// This provides an asynchronous read of the stack limits for the current
@@ -578,15 +578,22 @@ Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
}


static Handle<Map> MapForNewFunction(Isolate *isolate,
Handle<SharedFunctionInfo> function_info) {
Context *context = isolate->context()->native_context();
int map_index = Context::FunctionMapIndex(function_info->language_mode(),
function_info->is_generator());
return Handle<Map>(Map::cast(context->get(map_index)));
}


Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Context> context,
PretenureFlag pretenure) {
Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
function_info,
function_info->is_classic_mode()
? isolate()->function_map()
: isolate()->strict_mode_function_map(),
MapForNewFunction(isolate(), function_info),
pretenure);

if (function_info->ic_age() != isolate()->heap()->global_ic_age()) {
@@ -874,14 +881,7 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
initial_map->set_constructor(*function);
}

// Set function.prototype and give the prototype a constructor
// property that refers to the function.
SetPrototypeProperty(function, prototype);
// Currently safe because it is only invoked from Genesis.
CHECK_NOT_EMPTY_HANDLE(isolate(),
JSObject::SetLocalPropertyIgnoreAttributes(
prototype, constructor_string(),
function, DONT_ENUM));
return function;
}

@@ -119,6 +119,22 @@ struct JSArguments {
};
#endif

#if (defined CAN_USE_VFP3_INSTRUCTIONS) || !(defined ARM_TEST)
# define ENABLE_VFP3_DEFAULT true
#else
# define ENABLE_VFP3_DEFAULT false
#endif
#if (defined CAN_USE_ARMV7_INSTRUCTIONS) || !(defined ARM_TEST)
# define ENABLE_ARMV7_DEFAULT true
#else
# define ENABLE_ARMV7_DEFAULT false
#endif
#if (defined CAN_USE_VFP32DREGS) || !(defined ARM_TEST)
# define ENABLE_32DREGS_DEFAULT true
#else
# define ENABLE_32DREGS_DEFAULT false
#endif

#define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
#define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
#define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
@@ -168,12 +184,12 @@ DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
DEFINE_bool(compiled_transitions, false, "use optimizing compiler to "
"generate array elements transition stubs")
DEFINE_bool(compiled_keyed_stores, false, "use optimizing compiler to "
DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to "
"generate keyed store stubs")
DEFINE_bool(clever_optimizations,
true,
"Optimize object size, Array shift, DOM strings and string +")
DEFINE_bool(pretenure_literals, false, "allocate literals in old space")
DEFINE_bool(pretenure_literals, true, "allocate literals in old space")

// Flags for data representation optimizations
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
@@ -308,12 +324,9 @@ DEFINE_bool(enable_rdtsc, true,
"enable use of RDTSC instruction if available")
DEFINE_bool(enable_sahf, true,
"enable use of SAHF instruction if available (X64 only)")
DEFINE_bool(enable_vfp3, true,
"enable use of VFP3 instructions if available - this implies "
"enabling ARMv7 and VFP2 instructions (ARM only)")
DEFINE_bool(enable_vfp2, true,
"enable use of VFP2 instructions if available")
DEFINE_bool(enable_armv7, true,
DEFINE_bool(enable_vfp3, ENABLE_VFP3_DEFAULT,
"enable use of VFP3 instructions if available")
DEFINE_bool(enable_armv7, ENABLE_ARMV7_DEFAULT,
"enable use of ARMv7 instructions if available (ARM only)")
DEFINE_bool(enable_sudiv, true,
"enable use of SDIV and UDIV instructions if available (ARM only)")
@@ -322,10 +335,8 @@ DEFINE_bool(enable_movw_movt, false,
"instruction pairs (ARM only)")
DEFINE_bool(enable_unaligned_accesses, true,
"enable unaligned accesses for ARMv7 (ARM only)")
DEFINE_bool(enable_32dregs, true,
DEFINE_bool(enable_32dregs, ENABLE_32DREGS_DEFAULT,
"enable use of d16-d31 registers on ARM - this requires VFP3")
DEFINE_bool(enable_fpu, true,
"enable use of MIPS FPU instructions if available (MIPS only)")
DEFINE_bool(enable_vldr_imm, false,
"enable use of constant pools for double immediate (ARM only)")

@@ -502,6 +513,8 @@ DEFINE_int(sim_stack_alignment, 8,
"Stack alingment in bytes in simulator (4 or 8, 8 is default)")

// isolate.cc
DEFINE_bool(abort_on_uncaught_exception, false,
"abort program (dump core) when an uncaught exception is thrown")
DEFINE_bool(trace_exception, false,
"print stack trace when throwing exceptions")
DEFINE_bool(preallocate_message_memory, false,
@@ -34,6 +34,9 @@
#include "smart-pointers.h"
#include "string-stream.h"

#ifdef V8_TARGET_ARCH_ARM
#include "arm/assembler-arm-inl.h"
#endif

namespace v8 {
namespace internal {
@@ -305,7 +308,7 @@ static void SplitArgument(const char* arg,
// make a copy so we can NUL-terminate flag name
size_t n = arg - *name;
CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small
memcpy(buffer, *name, n);
OS::MemCopy(buffer, *name, n);
buffer[n] = '\0';
*name = buffer;
// get the value
@@ -367,8 +370,8 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
// sense there.
continue;
} else {
fprintf(stderr, "Error: unrecognized flag %s\n"
"Try --help for options\n", arg);
PrintF(stderr, "Error: unrecognized flag %s\n"
"Try --help for options\n", arg);
return_code = j;
break;
}
@@ -381,9 +384,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
if (i < *argc) {
value = argv[i++];
} else {
fprintf(stderr, "Error: missing value for flag %s of type %s\n"
"Try --help for options\n",
arg, Type2String(flag->type()));
PrintF(stderr, "Error: missing value for flag %s of type %s\n"
"Try --help for options\n",
arg, Type2String(flag->type()));
return_code = j;
break;
}
@@ -424,9 +427,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
(flag->type() != Flag::TYPE_BOOL && is_bool) ||
*endp != '\0') {
fprintf(stderr, "Error: illegal value for flag %s of type %s\n"
"Try --help for options\n",
arg, Type2String(flag->type()));
PrintF(stderr, "Error: illegal value for flag %s of type %s\n"
"Try --help for options\n",
arg, Type2String(flag->type()));
return_code = j;
break;
}
@@ -475,7 +478,7 @@ static char* SkipBlackSpace(char* p) {
int FlagList::SetFlagsFromString(const char* str, int len) {
// make a 0-terminated copy of str
ScopedVector<char> copy0(len + 1);
memcpy(copy0.start(), str, len);
OS::MemCopy(copy0.start(), str, len);
copy0[len] = '\0';

// strip leading white space
@@ -517,6 +520,12 @@ void FlagList::ResetAllFlags() {

// static
void FlagList::PrintHelp() {
#ifdef V8_TARGET_ARCH_ARM
CpuFeatures::PrintTarget();
CpuFeatures::Probe();
CpuFeatures::PrintFeatures();
#endif // V8_TARGET_ARCH_ARM

printf("Usage:\n");
printf(" shell [options] -e string\n");
printf(" execute string in V8\n");
@@ -84,6 +84,18 @@ class InnerPointerToCodeCache {
};


class StackHandlerConstants : public AllStatic {
public:
static const int kNextOffset = 0 * kPointerSize;
static const int kCodeOffset = 1 * kPointerSize;
static const int kStateOffset = 2 * kPointerSize;
static const int kContextOffset = 3 * kPointerSize;
static const int kFPOffset = 4 * kPointerSize;

static const int kSize = kFPOffset + kPointerSize;
};


class StackHandler BASE_EMBEDDED {
public:
enum Kind {
@@ -581,7 +593,6 @@ class JavaScriptFrame: public StandardFrame {
inline Object* function_slot_object() const;

friend class StackFrameIterator;
friend class StackTracer;
};


@@ -322,7 +322,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
ASSERT(!isolate->has_pending_exception());
return false;
}
unsigned table_offset = cgen.EmitStackCheckTable();
unsigned table_offset = cgen.EmitBackEdgeTable();

Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
@@ -341,8 +341,8 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
#endif // ENABLE_DEBUGGER_SUPPORT
code->set_allow_osr_at_loop_nesting_level(0);
code->set_profiler_ticks(0);
code->set_stack_check_table_offset(table_offset);
code->set_stack_check_patched_for_osr(false);
code->set_back_edge_table_offset(table_offset);
code->set_back_edges_patched_for_osr(false);
CodeGenerator::PrintCode(code, info);
info->SetCode(code); // May be an empty handle.
#ifdef ENABLE_GDB_JIT_INTERFACE
@@ -362,17 +362,18 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
}


unsigned FullCodeGenerator::EmitStackCheckTable() {
// The stack check table consists of a length (in number of entries)
unsigned FullCodeGenerator::EmitBackEdgeTable() {
// The back edge table consists of a length (in number of entries)
// field, and then a sequence of entries. Each entry is a pair of AST id
// and code-relative pc offset.
masm()->Align(kIntSize);
unsigned offset = masm()->pc_offset();
unsigned length = stack_checks_.length();
unsigned length = back_edges_.length();
__ dd(length);
for (unsigned i = 0; i < length; ++i) {
__ dd(stack_checks_[i].id.ToInt());
__ dd(stack_checks_[i].pc_and_state);
__ dd(back_edges_[i].id.ToInt());
__ dd(back_edges_[i].pc);
__ db(back_edges_[i].loop_depth);
}
return offset;
}
@@ -478,8 +479,11 @@ void FullCodeGenerator::RecordTypeFeedbackCell(
void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) {
// The pc offset does not need to be encoded and packed together with a state.
ASSERT(masm_->pc_offset() > 0);
BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) };
stack_checks_.Add(entry, zone());
ASSERT(loop_depth() > 0);
uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker);
BackEdgeEntry entry =
{ ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
back_edges_.Add(entry, zone());
}


@@ -1251,7 +1255,7 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
SetStatementPosition(stmt);
Label body, stack_check;
Label body, book_keeping;

Iteration loop_statement(this, stmt);
increment_loop_depth();
@@ -1265,13 +1269,13 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(),
&stack_check,
&book_keeping,
loop_statement.break_label(),
&stack_check);
&book_keeping);

// Check stack before looping.
PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
__ bind(&stack_check);
__ bind(&book_keeping);
EmitBackEdgeBookkeeping(stmt, &body);
__ jmp(&body);

@@ -1549,6 +1553,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
UNIMPLEMENTED();

Comment cmnt(masm_, "[ Yield");
// TODO(wingo): Actually update the iterator state.
VisitForEffect(expr->generator_object());
VisitForAccumulatorValue(expr->expression());
// TODO(wingo): Assert that the operand stack depth is 0, at least while
// general yield expressions are unimplemented.
@@ -92,7 +92,7 @@ class FullCodeGenerator: public AstVisitor {
bailout_entries_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0,
info->zone()),
stack_checks_(2, info->zone()), // There's always at least one.
back_edges_(2, info->zone()),
type_feedback_cells_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0,
info->zone()),
@@ -135,6 +135,7 @@ class FullCodeGenerator: public AstVisitor {
#error Unsupported target architecture.
#endif

static const int kBackEdgeEntrySize = 2 * kIntSize + kOneByteSize;

private:
class Breakable;
@@ -459,9 +460,9 @@ class FullCodeGenerator: public AstVisitor {
Label* back_edge_target);
// Record the OSR AST id corresponding to a back edge in the code.
void RecordBackEdge(BailoutId osr_ast_id);
// Emit a table of stack check ids and pcs into the code stream. Return
// the offset of the start of the table.
unsigned EmitStackCheckTable();
// Emit a table of back edge ids, pcs and loop depths into the code stream.
// Return the offset of the start of the table.
unsigned EmitBackEdgeTable();

void EmitProfilingCounterDecrement(int delta);
void EmitProfilingCounterReset();
@@ -624,6 +625,12 @@ class FullCodeGenerator: public AstVisitor {
unsigned pc_and_state;
};

struct BackEdgeEntry {
BailoutId id;
unsigned pc;
uint8_t loop_depth;
};

struct TypeFeedbackCellEntry {
TypeFeedbackId ast_id;
Handle<JSGlobalPropertyCell> cell;
@@ -818,9 +825,7 @@ class FullCodeGenerator: public AstVisitor {
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
GrowableBitVector prepared_bailout_ids_;
// TODO(svenpanne) Rename this to something like back_edges_ and rename
// related functions accordingly.
ZoneList<BailoutEntry> stack_checks_;
ZoneList<BackEdgeEntry> back_edges_;
ZoneList<TypeFeedbackCellEntry> type_feedback_cells_;
int ic_total_count_;
Handle<FixedArray> handler_table_;
@@ -629,7 +629,7 @@ class MachO BASE_EMBEDDED {
#if defined(__ELF)
class ELF BASE_EMBEDDED {
public:
ELF(Zone* zone) : sections_(6, zone) {
explicit ELF(Zone* zone) : sections_(6, zone) {
sections_.Add(new(zone) ELFSection("", ELFSection::TYPE_NULL, 0), zone);
sections_.Add(new(zone) ELFStringTable(".shstrtab"), zone);
}
@@ -681,7 +681,7 @@ class ELF BASE_EMBEDDED {
#else
#error Unsupported target architecture.
#endif
memcpy(header->ident, ident, 16);
OS::MemCopy(header->ident, ident, 16);
header->type = 1;
#if defined(V8_TARGET_ARCH_IA32)
header->machine = 3;
@@ -1019,9 +1019,9 @@ class CodeDescription BASE_EMBEDDED {

#if defined(__ELF)
static void CreateSymbolsTable(CodeDescription* desc,
Zone* zone,
ELF* elf,
int text_section_index) {
Zone* zone = desc->info()->zone();
ELFSymbolTable* symtab = new(zone) ELFSymbolTable(".symtab", zone);
ELFStringTable* strtab = new(zone) ELFStringTable(".strtab");

@@ -1213,8 +1213,11 @@ class DebugInfoSection : public DebugSection {
w->WriteSLEB128(StandardFrameConstants::kContextOffset);
block_size.set(static_cast<uint32_t>(w->position() - block_start));
}

w->WriteULEB128(0); // Terminate the sub program.
}

w->WriteULEB128(0); // Terminate the compile unit.
size.set(static_cast<uint32_t>(w->position() - start));
return true;
}
@@ -1324,15 +1327,14 @@ class DebugAbbrevSection : public DebugSection {
// The real slot ID is internal_slots + context_slot_id.
int internal_slots = Context::MIN_CONTEXT_SLOTS;
int locals = scope->StackLocalCount();
int total_children =
params + slots + context_slots + internal_slots + locals + 2;
// Total children is params + slots + context_slots + internal_slots +
// locals + 2 (__function and __context).

// The extra duplication below seems to be necessary to keep
// gdb from getting upset on OSX.
w->WriteULEB128(current_abbreviation++); // Abbreviation code.
w->WriteULEB128(DW_TAG_SUBPROGRAM);
w->Write<uint8_t>(
total_children != 0 ? DW_CHILDREN_YES : DW_CHILDREN_NO);
w->Write<uint8_t>(DW_CHILDREN_YES);
w->WriteULEB128(DW_AT_NAME);
w->WriteULEB128(DW_FORM_STRING);
w->WriteULEB128(DW_AT_LOW_PC);
@@ -1384,9 +1386,7 @@ class DebugAbbrevSection : public DebugSection {
// The context.
WriteVariableAbbreviation(w, current_abbreviation++, true, false);

if (total_children != 0) {
w->WriteULEB128(0); // Terminate the sibling list.
}
w->WriteULEB128(0); // Terminate the sibling list.
}

w->WriteULEB128(0); // Terminate the table.
@@ -1789,8 +1789,9 @@ bool UnwindInfoSection::WriteBodyInternal(Writer* w) {

#endif // V8_TARGET_ARCH_X64

static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) {
Zone* zone = desc->info()->zone();
static void CreateDWARFSections(CodeDescription* desc,
Zone* zone,
DebugObject* obj) {
if (desc->IsLineInfoAvailable()) {
obj->AddSection(new(zone) DebugInfoSection(desc), zone);
obj->AddSection(new(zone) DebugAbbrevSection(desc), zone);
@@ -1841,7 +1842,7 @@ extern "C" {
#ifdef OBJECT_PRINT
void __gdb_print_v8_object(MaybeObject* object) {
object->Print();
fprintf(stdout, "\n");
PrintF(stdout, "\n");
}
#endif
}
@@ -1854,7 +1855,7 @@ static JITCodeEntry* CreateCodeEntry(Address symfile_addr,

entry->symfile_addr_ = reinterpret_cast<Address>(entry + 1);
entry->symfile_size_ = symfile_size;
memcpy(entry->symfile_addr_, symfile_addr, symfile_size);
OS::MemCopy(entry->symfile_addr_, symfile_addr, symfile_size);

entry->prev_ = entry->next_ = NULL;

@@ -1915,8 +1916,7 @@ static void UnregisterCodeEntry(JITCodeEntry* entry) {
}


static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
Zone* zone = desc->info()->zone();
static JITCodeEntry* CreateELFObject(CodeDescription* desc, Zone* zone) {
ZoneScope zone_scope(zone, DELETE_ON_EXIT);
#ifdef __MACH_O
MachO mach_o;
@@ -1944,9 +1944,9 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC),
zone);

CreateSymbolsTable(desc, &elf, text_section_index);
CreateSymbolsTable(desc, zone, &elf, text_section_index);

CreateDWARFSections(desc, &elf);
CreateDWARFSections(desc, zone, &elf);

elf.Write(&w);
#endif
@@ -2083,7 +2083,8 @@ void GDBJITInterface::AddCode(const char* name,
}

AddUnwindInfo(&code_desc);
JITCodeEntry* entry = CreateELFObject(&code_desc);
Zone* zone = code->GetIsolate()->runtime_zone();
JITCodeEntry* entry = CreateELFObject(&code_desc, zone);
ASSERT(!IsLineInfoTagged(entry));

delete lineinfo;
@@ -0,0 +1,74 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"use strict";

// This file relies on the fact that the following declarations have been made
// in runtime.js:
// var $Function = global.Function;

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


// TODO(wingo): Give link to specification. For now, the following diagram is
// the spec:
// http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png

function GeneratorObjectNext() {
// TODO(wingo): Implement.
}

function GeneratorObjectSend(value) {
// TODO(wingo): Implement.
}

function GeneratorObjectThrow(exn) {
// TODO(wingo): Implement.
}

function GeneratorObjectClose() {
// TODO(wingo): Implement.
}

function SetUpGenerators() {
%CheckIsBootstrapping();
var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
InstallFunctions(GeneratorObjectPrototype,
DONT_ENUM | DONT_DELETE | READ_ONLY,
["next", GeneratorObjectNext,
"send", GeneratorObjectSend,
"throw", GeneratorObjectThrow,
"close", GeneratorObjectClose]);
%SetProperty(GeneratorObjectPrototype, "constructor",
GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetPrototype(GeneratorFunctionPrototype, $Function.prototype);
%SetProperty(GeneratorFunctionPrototype, "constructor",
GeneratorFunction, DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetPrototype(GeneratorFunction, $Function);
}

SetUpGenerators();
@@ -31,10 +31,15 @@
#include "../include/v8-profiler.h"

#include "list.h"
#include "v8utils.h"

namespace v8 {
namespace internal {

class GCTracer;
class HeapStats;
class ObjectVisitor;

// Structure for tracking global handles.
// A single list keeps all the allocated global handles.
// Destroyed handles stay in the list but is added to the free list.
@@ -88,7 +93,7 @@ class ImplicitRefGroup {
malloc(OFFSET_OF(ImplicitRefGroup, children_[length])));
group->parent_ = parent;
group->length_ = length;
CopyWords(group->children_, children, static_cast<int>(length));
CopyWords(group->children_, children, length);
return group;
}

@@ -67,9 +67,21 @@ namespace internal {
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
#if defined(__native_client__)
// For Native Client builds of V8, use V8_TARGET_ARCH_ARM, so that V8
// generates ARM machine code, together with a portable ARM simulator
// compiled for the host architecture in question.
//
// Since Native Client is ILP-32 on all architectures we use
// V8_HOST_ARCH_IA32 on both 32- and 64-bit x86.
#define V8_HOST_ARCH_IA32 1
#define V8_HOST_ARCH_32_BIT 1
#define V8_HOST_CAN_READ_UNALIGNED 1
#else
#define V8_HOST_ARCH_X64 1
#define V8_HOST_ARCH_64_BIT 1
#define V8_HOST_CAN_READ_UNALIGNED 1
#endif // __native_client__
#elif defined(_M_IX86) || defined(__i386__)
#define V8_HOST_ARCH_IA32 1
#define V8_HOST_ARCH_32_BIT 1
@@ -59,7 +59,6 @@ inline bool Handle<T>::is_identical_to(const Handle<T> other) const {
if (FLAG_enable_slow_asserts) {
Isolate* isolate = Isolate::Current();
CHECK(isolate->AllowHandleDereference() ||
Heap::RelocationLock::IsLocked(isolate->heap()) ||
!isolate->optimizing_compiler_thread()->IsOptimizerThread());
}
#endif // DEBUG
@@ -252,15 +252,32 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
}


Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) {
Isolate* isolate = object->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
Runtime::DeleteObjectProperty(
isolate, object, key, JSReceiver::NORMAL_DELETION),
Object);
}


Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key) {
Isolate* isolate = object->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
Runtime::ForceDeleteObjectProperty(isolate, object, key),
Runtime::DeleteObjectProperty(
isolate, object, key, JSReceiver::FORCE_DELETION),
Object);
}


Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) {
Isolate* isolate = obj->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
Runtime::HasObjectProperty(isolate, obj, key), Object);
}


Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name) {
Isolate* isolate = obj->GetIsolate();
@@ -308,6 +325,14 @@ Handle<JSObject> Copy(Handle<JSObject> obj) {
}


Handle<JSObject> DeepCopy(Handle<JSObject> obj) {
Isolate* isolate = obj->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
obj->DeepCopy(isolate),
JSObject);
}


Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
}
@@ -223,11 +223,13 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
Handle<Object> value,
PropertyAttributes attributes);

Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key);
Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key);

Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name);
Handle<Object> ForceDeleteProperty(Handle<JSObject> object, Handle<Object> key);

Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key);

Handle<Object> GetProperty(Handle<JSReceiver> obj, const char* name);

Handle<Object> GetProperty(Isolate* isolate,
Handle<Object> obj,
@@ -240,6 +242,8 @@ Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,

Handle<JSObject> Copy(Handle<JSObject> obj);

Handle<JSObject> DeepCopy(Handle<JSObject> obj);

Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info);

Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray>,
@@ -159,8 +159,8 @@ MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
ASSERT_EQ(size, answer->Size());

// Fill in the characters.
memcpy(answer->address() + SeqOneByteString::kHeaderSize,
str.start(), str.length());
OS::MemCopy(answer->address() + SeqOneByteString::kHeaderSize,
str.start(), str.length());

return answer;
}
@@ -192,8 +192,8 @@ MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
ASSERT_EQ(size, answer->Size());

// Fill in the characters.
memcpy(answer->address() + SeqTwoByteString::kHeaderSize,
str.start(), str.length() * kUC16Size);
OS::MemCopy(answer->address() + SeqTwoByteString::kHeaderSize,
str.start(), str.length() * kUC16Size);

return answer;
}
@@ -345,6 +345,16 @@ bool Heap::InOldPointerSpace(Object* object) {
}


bool Heap::InOldDataSpace(Address address) {
return old_data_space_->Contains(address);
}


bool Heap::InOldDataSpace(Object* object) {
return InOldDataSpace(reinterpret_cast<Address>(object));
}


bool Heap::OldGenerationAllocationLimitReached() {
if (!incremental_marking()->IsStopped()) return false;
return OldGenerationSpaceAvailable() < 0;
@@ -417,7 +427,7 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) {
void Heap::CopyBlock(Address dst, Address src, int byte_size) {
CopyWords(reinterpret_cast<Object**>(dst),
reinterpret_cast<Object**>(src),
byte_size / kPointerSize);
static_cast<size_t>(byte_size / kPointerSize));
}


@@ -435,7 +445,7 @@ void Heap::MoveBlock(Address dst, Address src, int byte_size) {
*dst_slot++ = *src_slot++;
}
} else {
memmove(dst, src, byte_size);
OS::MemMove(dst, src, static_cast<size_t>(byte_size));
}
}

@@ -2319,7 +2319,7 @@ class OutputStreamWriter {
int s_chunk_size = Min(
chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
ASSERT(s_chunk_size > 0);
memcpy(chunk_.start() + chunk_pos_, s, s_chunk_size);
OS::MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
s += s_chunk_size;
chunk_pos_ += s_chunk_size;
MaybeWriteChunk();
@@ -162,8 +162,7 @@ Heap::Heap()
#endif
promotion_queue_(this),
configured_(false),
chunks_queued_for_free_(NULL),
relocation_mutex_(NULL) {
chunks_queued_for_free_(NULL) {
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
// easier if you can define it as part of the build environment.
@@ -688,9 +687,9 @@ void Heap::MoveElements(FixedArray* array,

ASSERT(array->map() != HEAP->fixed_cow_array_map());
Object** dst_objects = array->data_start() + dst_index;
memmove(dst_objects,
array->data_start() + src_index,
len * kPointerSize);
OS::MemMove(dst_objects,
array->data_start() + src_index,
len * kPointerSize);
if (!InNewSpace(array)) {
for (int i = 0; i < len; i++) {
// TODO(hpayer): check store buffer for entries
@@ -952,6 +951,13 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
PrintPID("Limited new space size due to high promotion rate: %d MB\n",
new_space_.InitialCapacity() / MB);
}
// Support for global pre-tenuring uses the high promotion mode as a
// heuristic indicator of whether to pretenure or not, we trigger
// deoptimization here to take advantage of pre-tenuring as soon as
// possible.
if (FLAG_pretenure_literals) {
isolate_->stack_guard()->FullDeopt();
}
} else if (new_space_high_promotion_mode_active_ &&
IsStableOrDecreasingSurvivalTrend() &&
IsLowSurvivalRate()) {
@@ -963,6 +969,11 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
new_space_.MaximumCapacity() / MB);
}
// Trigger deoptimization here to turn off pre-tenuring as soon as
// possible.
if (FLAG_pretenure_literals) {
isolate_->stack_guard()->FullDeopt();
}
}

if (new_space_high_promotion_mode_active_ &&
@@ -1282,8 +1293,6 @@ class ScavengeWeakObjectRetainer : public WeakObjectRetainer {


void Heap::Scavenge() {
RelocationLock relocation_lock(this);

#ifdef VERIFY_HEAP
if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
#endif
@@ -2836,13 +2845,6 @@ bool Heap::CreateInitialObjects() {
}
hidden_string_ = String::cast(obj);

// Allocate the foreign for __proto__.
{ MaybeObject* maybe_obj =
AllocateForeign((Address) &Accessors::ObjectPrototype);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_prototype_accessors(Foreign::cast(obj));

// Allocate the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping.
{ MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(this, 128);
@@ -3963,30 +3965,36 @@ void Heap::InitializeFunction(JSFunction* function,


MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
// Allocate the prototype. Make sure to use the object function
// from the function's context, since the function can be from a
// different context.
JSFunction* object_function =
function->context()->native_context()->object_function();

// Each function prototype gets a copy of the object function map.
// This avoid unwanted sharing of maps between prototypes of different
// constructors.
// Make sure to use globals from the function's context, since the function
// can be from a different context.
Context* native_context = function->context()->native_context();
bool needs_constructor_property;
Map* new_map;
ASSERT(object_function->has_initial_map());
MaybeObject* maybe_map = object_function->initial_map()->Copy();
if (!maybe_map->To(&new_map)) return maybe_map;
if (function->shared()->is_generator()) {
// Generator prototypes can share maps since they don't have "constructor"
// properties.
new_map = native_context->generator_object_prototype_map();
needs_constructor_property = false;
} else {
// Each function prototype gets a fresh map to avoid unwanted sharing of
// maps between prototypes of different constructors.
JSFunction* object_function = native_context->object_function();
ASSERT(object_function->has_initial_map());
MaybeObject* maybe_map = object_function->initial_map()->Copy();
if (!maybe_map->To(&new_map)) return maybe_map;
needs_constructor_property = true;
}

Object* prototype;
MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;

// When creating the prototype for the function we must set its
// constructor to the function.
MaybeObject* maybe_failure =
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
constructor_string(), function, DONT_ENUM);
if (maybe_failure->IsFailure()) return maybe_failure;
if (needs_constructor_property) {
MaybeObject* maybe_failure =
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
constructor_string(), function, DONT_ENUM);
if (maybe_failure->IsFailure()) return maybe_failure;
}

return prototype;
}
@@ -4086,10 +4094,20 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {

// First create a new map with the size and number of in-object properties
// suggested by the function.
int instance_size = fun->shared()->CalculateInstanceSize();
int in_object_properties = fun->shared()->CalculateInObjectProperties();
InstanceType instance_type;
int instance_size;
int in_object_properties;
if (fun->shared()->is_generator()) {
instance_type = JS_GENERATOR_OBJECT_TYPE;
instance_size = JSGeneratorObject::kSize;
in_object_properties = 0;
} else {
instance_type = JS_OBJECT_TYPE;
instance_size = fun->shared()->CalculateInstanceSize();
in_object_properties = fun->shared()->CalculateInObjectProperties();
}
Map* map;
MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
MaybeObject* maybe_map = AllocateMap(instance_type, instance_size);
if (!maybe_map->To(&map)) return maybe_map;

// Fetch or allocate prototype.
@@ -4111,7 +4129,8 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
// the inline_new flag so we only change the map if we generate a
// specialized construct stub.
ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
if (instance_type == JS_OBJECT_TYPE &&
fun->shared()->CanGenerateInlineConstructor(prototype)) {
int count = fun->shared()->this_property_assignments_count();
if (count > in_object_properties) {
// Inline constructor can only handle inobject properties.
@@ -4144,7 +4163,9 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
}
}

fun->shared()->StartInobjectSlackTracking(map);
if (instance_type == JS_OBJECT_TYPE) {
fun->shared()->StartInobjectSlackTracking(map);
}

return map;
}
@@ -4327,6 +4348,22 @@ MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
}


MaybeObject* Heap::AllocateJSGeneratorObject(JSFunction *function) {
ASSERT(function->shared()->is_generator());
Map *map;
if (function->has_initial_map()) {
map = function->initial_map();
} else {
// Allocate the initial map if absent.
MaybeObject* maybe_map = AllocateInitialMap(function);
if (!maybe_map->To(&map)) return maybe_map;
function->set_initial_map(map);
}
ASSERT(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
return AllocateJSObjectFromMap(map);
}


MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
// Allocate a fresh map. Modules do not have a prototype.
Map* map;
@@ -4945,7 +4982,7 @@ static inline void WriteOneByteData(Vector<const char> vector,
int len) {
// Only works for ascii.
ASSERT(vector.length() == len);
memcpy(chars, vector.start(), len);
OS::MemCopy(chars, vector.start(), len);
}

static inline void WriteTwoByteData(Vector<const char> vector,
@@ -6588,11 +6625,6 @@ bool Heap::SetUp() {

store_buffer()->SetUp();

if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
#ifdef DEBUG
relocation_mutex_locked_ = false;
#endif // DEBUG

return true;
}

@@ -6695,8 +6727,6 @@ void Heap::TearDown() {
incremental_marking()->TearDown();

isolate_->memory_allocator()->TearDown();

delete relocation_mutex_;
}


@@ -7821,8 +7851,8 @@ void Heap::CheckpointObjectStats() {
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
#undef ADJUST_LAST_TIME_OBJECT_COUNT

memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
ClearObjectStats();
}

@@ -150,7 +150,6 @@ namespace internal {
V(HeapNumber, minus_zero_value, MinusZeroValue) \
V(Map, neander_map, NeanderMap) \
V(JSObject, message_listeners, MessageListeners) \
V(Foreign, prototype_accessors, PrototypeAccessors) \
V(UnseededNumberDictionary, code_stubs, CodeStubs) \
V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache) \
@@ -210,9 +209,11 @@ namespace internal {
V(index_string, "index") \
V(last_index_string, "lastIndex") \
V(object_string, "object") \
V(payload_string, "payload") \
V(prototype_string, "prototype") \
V(string_string, "string") \
V(String_string, "String") \
V(unknown_field_string, "unknownField") \
V(symbol_string, "symbol") \
V(Symbol_string, "Symbol") \
V(Date_string, "Date") \
@@ -601,6 +602,13 @@ class Heap {
return old_pointer_space_->allocation_limit_address();
}

Address* OldDataSpaceAllocationTopAddress() {
return old_data_space_->allocation_top_address();
}
Address* OldDataSpaceAllocationLimitAddress() {
return old_data_space_->allocation_limit_address();
}

// Uncommit unused semi space.
bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); }

@@ -617,6 +625,9 @@ class Heap {
JSFunction* constructor,
Handle<Object> allocation_site_info_payload);

MUST_USE_RESULT MaybeObject* AllocateJSGeneratorObject(
JSFunction* function);

MUST_USE_RESULT MaybeObject* AllocateJSModule(Context* context,
ScopeInfo* scope_info);

@@ -1329,6 +1340,10 @@ class Heap {
inline bool InOldPointerSpace(Address address);
inline bool InOldPointerSpace(Object* object);

// Returns whether the object resides in old data space.
inline bool InOldDataSpace(Address address);
inline bool InOldDataSpace(Object* object);

// Checks whether an address/object in the heap (including auxiliary
// area and unused area).
bool Contains(Address addr);
@@ -1497,6 +1512,12 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
PretenureFlag pretenure);

// Predicate that governs global pre-tenuring decisions based on observed
// promotion rates of previous collections.
inline bool ShouldGloballyPretenure() {
return new_space_high_promotion_mode_active_;
}

inline intptr_t PromotedTotalSize() {
return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize();
}
@@ -1825,38 +1846,6 @@ class Heap {

void CheckpointObjectStats();

// We don't use a ScopedLock here since we want to lock the heap
// only when FLAG_parallel_recompilation is true.
class RelocationLock {
public:
explicit RelocationLock(Heap* heap) : heap_(heap) {
if (FLAG_parallel_recompilation) {
heap_->relocation_mutex_->Lock();
#ifdef DEBUG
heap_->relocation_mutex_locked_ = true;
#endif // DEBUG
}
}

~RelocationLock() {
if (FLAG_parallel_recompilation) {
#ifdef DEBUG
heap_->relocation_mutex_locked_ = false;
#endif // DEBUG
heap_->relocation_mutex_->Unlock();
}
}

#ifdef DEBUG
static bool IsLocked(Heap* heap) {
return heap->relocation_mutex_locked_;
}
#endif // DEBUG

private:
Heap* heap_;
};

private:
Heap();

@@ -2326,11 +2315,6 @@ class Heap {

MemoryChunk* chunks_queued_for_free_;

Mutex* relocation_mutex_;
#ifdef DEBUG
bool relocation_mutex_locked_;
#endif // DEBUG;

friend class Factory;
friend class GCTracer;
friend class DisallowAllocationFailure;
@@ -685,7 +685,7 @@ void HValue::Kill() {
HValue* operand = OperandAt(i);
if (operand == NULL) continue;
HUseListNode* first = operand->use_list_;
if (first != NULL && first->value() == this && first->index() == i) {
if (first != NULL && first->value()->CheckFlag(kIsDead)) {
operand->use_list_ = first->tail();
}
}
@@ -806,6 +806,9 @@ void HInstruction::PrintTo(StringStream* stream) {
PrintRangeTo(stream);
PrintChangesTo(stream);
PrintTypeTo(stream);
if (CheckFlag(HValue::kHasNoObservableSideEffects)) {
stream->Add(" [noOSE]");
}
}


@@ -1581,10 +1584,10 @@ void HCheckMaps::SetSideEffectDominator(GVNFlag side_effect,
// for which the map is known.
if (HasNoUses() && dominator->IsStoreNamedField()) {
HStoreNamedField* store = HStoreNamedField::cast(dominator);
Handle<Map> map = store->transition();
if (map.is_null() || store->object() != value()) return;
UniqueValueId map_unique_id = store->transition_unique_id();
if (!map_unique_id.IsInitialized() || store->object() != value()) return;
for (int i = 0; i < map_set()->length(); i++) {
if (map.is_identical_to(map_set()->at(i))) {
if (map_unique_id == map_unique_ids_.at(i)) {
DeleteAndReplaceWith(NULL);
return;
}
@@ -1980,20 +1983,25 @@ void HPhi::AddIndirectUsesTo(int* dest) {
}


void HSimulate::MergeInto(HSimulate* other) {
for (int i = 0; i < values_.length(); ++i) {
HValue* value = values_[i];
if (HasAssignedIndexAt(i)) {
other->AddAssignedValue(GetAssignedIndexAt(i), value);
} else {
if (other->pop_count_ > 0) {
other->pop_count_--;
void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
while (!list->is_empty()) {
HSimulate* from = list->RemoveLast();
ZoneList<HValue*>* from_values = &from->values_;
for (int i = 0; i < from_values->length(); ++i) {
if (from->HasAssignedIndexAt(i)) {
AddAssignedValue(from->GetAssignedIndexAt(i),
from_values->at(i));
} else {
other->AddPushedValue(value);
if (pop_count_ > 0) {
pop_count_--;
} else {
AddPushedValue(from_values->at(i));
}
}
}
pop_count_ += from->pop_count_;
from->DeleteAndReplaceWith(NULL);
}
other->pop_count_ += pop_count();
}


@@ -2039,6 +2047,7 @@ static bool IsInteger32(double value) {

HConstant::HConstant(Handle<Object> handle, Representation r)
: handle_(handle),
unique_id_(),
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(false),
@@ -2067,11 +2076,13 @@ HConstant::HConstant(Handle<Object> handle, Representation r)


HConstant::HConstant(Handle<Object> handle,
UniqueValueId unique_id,
Representation r,
HType type,
bool is_internalize_string,
bool boolean_value)
: handle_(handle),
unique_id_(unique_id),
has_int32_value_(false),
has_double_value_(false),
is_internalized_string_(is_internalize_string),
@@ -2087,7 +2098,9 @@ HConstant::HConstant(Handle<Object> handle,
HConstant::HConstant(int32_t integer_value,
Representation r,
Handle<Object> optional_handle)
: has_int32_value_(true),
: handle_(optional_handle),
unique_id_(),
has_int32_value_(true),
has_double_value_(true),
is_internalized_string_(false),
boolean_value_(integer_value != 0),
@@ -2100,7 +2113,9 @@ HConstant::HConstant(int32_t integer_value,
HConstant::HConstant(double double_value,
Representation r,
Handle<Object> optional_handle)
: has_int32_value_(IsInteger32(double_value)),
: handle_(optional_handle),
unique_id_(),
has_int32_value_(IsInteger32(double_value)),
has_double_value_(true),
is_internalized_string_(false),
boolean_value_(double_value != 0 && !isnan(double_value)),
@@ -2125,8 +2140,12 @@ HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
if (has_int32_value_) return new(zone) HConstant(int32_value_, r, handle_);
if (has_double_value_) return new(zone) HConstant(double_value_, r, handle_);
ASSERT(!handle_.is_null());
return new(zone) HConstant(
handle_, r, type_from_value_, is_internalized_string_, boolean_value_);
return new(zone) HConstant(handle_,
unique_id_,
r,
type_from_value_,
is_internalized_string_,
boolean_value_);
}


@@ -2451,6 +2470,8 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
Zone* zone)
: types_(Min(types->length(), kMaxLoadPolymorphism), zone),
name_(name),
types_unique_ids_(0, zone),
name_unique_id_(),
need_generic_(false) {
SetOperandAt(0, context);
SetOperandAt(1, object);
@@ -2517,15 +2538,39 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
}


void HCheckMaps::FinalizeUniqueValueId() {
if (!map_unique_ids_.is_empty()) return;
Zone* zone = block()->zone();
map_unique_ids_.Initialize(map_set_.length(), zone);
for (int i = 0; i < map_set_.length(); i++) {
map_unique_ids_.Add(UniqueValueId(map_set_.at(i)), zone);
}
}


void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() {
if (!types_unique_ids_.is_empty()) return;
Zone* zone = block()->zone();
types_unique_ids_.Initialize(types_.length(), zone);
for (int i = 0; i < types_.length(); i++) {
types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone);
}
name_unique_id_ = UniqueValueId(name_);
}


bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
ASSERT_EQ(types_.length(), types_unique_ids_.length());
HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
if (types_.length() != other->types()->length()) return false;
if (!name_.is_identical_to(other->name())) return false;
if (name_unique_id_ != other->name_unique_id_) return false;
if (types_unique_ids_.length() != other->types_unique_ids_.length()) {
return false;
}
if (need_generic_ != other->need_generic_) return false;
for (int i = 0; i < types_.length(); i++) {
for (int i = 0; i < types_unique_ids_.length(); i++) {
bool found = false;
for (int j = 0; j < types_.length(); j++) {
if (types_.at(j).is_identical_to(other->types()->at(i))) {
for (int j = 0; j < types_unique_ids_.length(); j++) {
if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) {
found = true;
break;
}
@@ -2916,12 +2961,6 @@ void HAllocate::PrintDataTo(StringStream* stream) {
}


HType HFastLiteral::CalculateInferredType() {
// TODO(mstarzinger): Be smarter, could also be JSArray here.
return HType::JSObject();
}


HType HArrayLiteral::CalculateInferredType() {
return HType::JSArray();
}