aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-11-30 16:04:58 +0000
committerBen Murdoch <benm@google.com>2011-12-02 17:28:30 +0000
commit589d6979ff2ef66fca2d8fa51404c369ca5e9250 (patch)
tree1d9032fcae9d18a05430a4ba9c14e5c635c4096e /src
parent69a99ed0b2b2ef69d393c371b03db3a98aaf880e (diff)
downloadv8-589d6979ff2ef66fca2d8fa51404c369ca5e9250.tar.gz
Upgrade to V8 3.6
Merge V8 at 3.6.6.11 Simple merge required updates to makefiles only. Bug: 5688872 Change-Id: Ib38b7ffbcd409585f6cb6fccc59c767029cecc77
Diffstat (limited to 'src')
-rw-r--r--src/SConscript18
-rw-r--r--src/accessors.cc3
-rw-r--r--src/api.cc42
-rw-r--r--src/arguments.h1
-rw-r--r--src/arm/builtins-arm.cc86
-rw-r--r--src/arm/code-stubs-arm.cc250
-rw-r--r--src/arm/full-codegen-arm.cc640
-rw-r--r--src/arm/ic-arm.cc20
-rw-r--r--src/arm/lithium-arm.cc47
-rw-r--r--src/arm/lithium-arm.h7
-rw-r--r--src/arm/lithium-codegen-arm.cc102
-rw-r--r--src/arm/lithium-gap-resolver-arm.h1
-rw-r--r--src/arm/macro-assembler-arm.cc66
-rw-r--r--src/arm/macro-assembler-arm.h14
-rw-r--r--src/arm/regexp-macro-assembler-arm.h1
-rw-r--r--src/arm/stub-cache-arm.cc160
-rw-r--r--src/array.js49
-rw-r--r--src/ast.cc43
-rw-r--r--src/ast.h145
-rw-r--r--src/bignum-dtoa.cc7
-rw-r--r--src/bignum.h1
-rw-r--r--src/bootstrapper.cc14
-rw-r--r--src/builtins.cc1
-rw-r--r--src/builtins.h2
-rw-r--r--src/cached-powers.h1
-rw-r--r--src/circular-queue-inl.h8
-rw-r--r--src/code-stubs.cc65
-rw-r--r--src/code-stubs.h32
-rw-r--r--src/compilation-cache.h1
-rw-r--r--src/compiler.cc1
-rw-r--r--src/compiler.h10
-rw-r--r--src/conversions-inl.h22
-rw-r--r--src/conversions.cc5
-rw-r--r--src/conversions.h11
-rw-r--r--src/cpu-profiler-inl.h5
-rw-r--r--src/cpu-profiler.cc11
-rw-r--r--src/cpu-profiler.h9
-rw-r--r--src/d8-debug.cc16
-rw-r--r--src/d8-debug.h8
-rw-r--r--src/d8-posix.cc1
-rw-r--r--src/d8-readline.cc23
-rw-r--r--src/d8.cc209
-rw-r--r--src/d8.h73
-rw-r--r--src/d8.js2
-rw-r--r--src/date.js11
-rw-r--r--src/dateparser.h5
-rw-r--r--src/debug-agent.cc17
-rw-r--r--src/debug-agent.h4
-rw-r--r--src/debug.cc78
-rw-r--r--src/debug.h6
-rw-r--r--src/deoptimizer.cc8
-rw-r--r--src/disassembler.cc5
-rw-r--r--src/dtoa.cc7
-rw-r--r--src/elements.cc24
-rw-r--r--src/elements.h4
-rw-r--r--src/execution.cc65
-rw-r--r--src/execution.h7
-rw-r--r--src/extensions/externalize-string-extension.cc6
-rw-r--r--src/factory.cc21
-rw-r--r--src/factory.h11
-rw-r--r--src/fast-dtoa.cc6
-rw-r--r--src/fixed-dtoa.cc6
-rw-r--r--src/flags.cc6
-rw-r--r--src/frames.h1
-rw-r--r--src/full-codegen.cc96
-rw-r--r--src/full-codegen.h89
-rw-r--r--src/gdb-jit.cc4
-rw-r--r--src/globals.h33
-rw-r--r--src/handles.cc17
-rw-r--r--src/handles.h2
-rw-r--r--src/heap.cc155
-rw-r--r--src/heap.h43
-rw-r--r--src/hydrogen-instructions.cc78
-rw-r--r--src/hydrogen-instructions.h56
-rw-r--r--src/hydrogen.cc635
-rw-r--r--src/hydrogen.h25
-rw-r--r--src/ia32/assembler-ia32.h3
-rw-r--r--src/ia32/builtins-ia32.cc89
-rw-r--r--src/ia32/code-stubs-ia32.cc61
-rw-r--r--src/ia32/full-codegen-ia32.cc689
-rw-r--r--src/ia32/ic-ia32.cc19
-rw-r--r--src/ia32/lithium-codegen-ia32.cc103
-rw-r--r--src/ia32/lithium-codegen-ia32.h2
-rw-r--r--src/ia32/lithium-ia32.cc49
-rw-r--r--src/ia32/lithium-ia32.h7
-rw-r--r--src/ia32/macro-assembler-ia32.cc30
-rw-r--r--src/ia32/macro-assembler-ia32.h4
-rw-r--r--src/ia32/stub-cache-ia32.cc86
-rw-r--r--src/ic.cc52
-rw-r--r--src/ic.h9
-rw-r--r--src/inspector.h2
-rw-r--r--src/isolate.cc15
-rw-r--r--src/isolate.h26
-rw-r--r--src/json.js13
-rw-r--r--src/jsregexp.cc8
-rw-r--r--src/jsregexp.h10
-rw-r--r--src/list-inl.h29
-rw-r--r--src/list.h10
-rw-r--r--src/lithium.cc28
-rw-r--r--src/lithium.h8
-rw-r--r--src/liveedit.cc9
-rw-r--r--src/liveobjectlist.cc18
-rw-r--r--src/liveobjectlist.h3
-rw-r--r--src/log-utils.cc2
-rw-r--r--src/log-utils.h1
-rw-r--r--src/log.cc110
-rw-r--r--src/log.h2
-rw-r--r--src/macros.py30
-rw-r--r--src/math.js14
-rw-r--r--src/messages.cc7
-rw-r--r--src/messages.h2
-rw-r--r--src/messages.js575
-rw-r--r--src/mips/assembler-mips-inl.h13
-rw-r--r--src/mips/assembler-mips.cc256
-rw-r--r--src/mips/assembler-mips.h84
-rw-r--r--src/mips/builtins-mips.cc12
-rw-r--r--src/mips/code-stubs-mips.cc236
-rw-r--r--src/mips/constants-mips.cc9
-rw-r--r--src/mips/constants-mips.h56
-rw-r--r--src/mips/disasm-mips.cc19
-rw-r--r--src/mips/frames-mips.h114
-rw-r--r--src/mips/full-codegen-mips.cc633
-rw-r--r--src/mips/ic-mips.cc25
-rw-r--r--src/mips/macro-assembler-mips.cc164
-rw-r--r--src/mips/macro-assembler-mips.h21
-rw-r--r--src/mips/regexp-macro-assembler-mips.h1
-rw-r--r--src/mips/simulator-mips.cc7
-rw-r--r--src/mips/stub-cache-mips.cc166
-rw-r--r--src/mksnapshot.cc12
-rw-r--r--src/objects-debug.cc18
-rw-r--r--src/objects-inl.h113
-rw-r--r--src/objects-printer.cc16
-rw-r--r--src/objects-visiting.cc5
-rw-r--r--src/objects.cc155
-rw-r--r--src/objects.h232
-rw-r--r--src/parser.cc203
-rw-r--r--src/parser.h14
-rw-r--r--src/platform-cygwin.cc1
-rw-r--r--src/platform-freebsd.cc1
-rw-r--r--src/platform-linux.cc6
-rw-r--r--src/platform-macos.cc1
-rw-r--r--src/platform-solaris.cc1
-rw-r--r--src/platform-win32.cc72
-rw-r--r--src/platform.h69
-rw-r--r--src/preparser-api.cc8
-rw-r--r--src/preparser.cc270
-rw-r--r--src/preparser.h103
-rw-r--r--src/prettyprinter.cc126
-rw-r--r--src/prettyprinter.h3
-rw-r--r--src/profile-generator-inl.h16
-rw-r--r--src/profile-generator.cc32
-rw-r--r--src/profile-generator.h7
-rw-r--r--src/property.cc6
-rw-r--r--src/property.h16
-rw-r--r--src/proxy.js51
-rw-r--r--src/regexp-macro-assembler-irregexp.h1
-rw-r--r--src/regexp-macro-assembler-tracer.h1
-rw-r--r--src/regexp-stack.h1
-rw-r--r--src/regexp.js6
-rw-r--r--src/rewriter.cc1
-rw-r--r--src/runtime-profiler.cc6
-rw-r--r--src/runtime.cc617
-rw-r--r--src/runtime.h18
-rw-r--r--src/runtime.js45
-rw-r--r--src/safepoint-table.cc4
-rw-r--r--src/scanner-base.cc1090
-rw-r--r--src/scanner-base.h562
-rw-r--r--src/scanner-character-streams.cc307
-rw-r--r--src/scanner-character-streams.h129
-rw-r--r--src/scanner.cc1215
-rw-r--r--src/scanner.h559
-rw-r--r--src/scopeinfo.cc65
-rw-r--r--src/scopeinfo.h2
-rw-r--r--src/scopes.cc153
-rw-r--r--src/scopes.h19
-rw-r--r--src/serialize.cc7
-rw-r--r--src/smart-array-pointer.h (renamed from src/smart-pointer.h)59
-rw-r--r--src/spaces.h3
-rw-r--r--src/splay-tree.h5
-rw-r--r--src/string-stream.cc4
-rw-r--r--src/string-stream.h3
-rw-r--r--src/string.js71
-rw-r--r--src/strtod.cc3
-rw-r--r--src/stub-cache.cc83
-rw-r--r--src/stub-cache.h25
-rw-r--r--src/type-info.cc1
-rw-r--r--src/uri.js7
-rw-r--r--src/utils.h105
-rw-r--r--src/v8conversions.cc1
-rw-r--r--src/v8globals.h12
-rw-r--r--src/v8natives.js302
-rw-r--r--src/v8threads.h1
-rw-r--r--src/variables.cc31
-rw-r--r--src/variables.h55
-rw-r--r--src/version.cc6
-rw-r--r--src/weakmap.js11
-rw-r--r--src/win32-math.cc106
-rw-r--r--src/win32-math.h61
-rw-r--r--src/x64/assembler-x64.h3
-rw-r--r--src/x64/builtins-x64.cc77
-rw-r--r--src/x64/code-stubs-x64.cc134
-rw-r--r--src/x64/full-codegen-x64.cc682
-rw-r--r--src/x64/ic-x64.cc19
-rw-r--r--src/x64/lithium-codegen-x64.cc102
-rw-r--r--src/x64/lithium-codegen-x64.h2
-rw-r--r--src/x64/lithium-x64.cc47
-rw-r--r--src/x64/lithium-x64.h7
-rw-r--r--src/x64/macro-assembler-x64.cc62
-rw-r--r--src/x64/macro-assembler-x64.h13
-rw-r--r--src/x64/stub-cache-x64.cc92
-rw-r--r--src/zone-inl.h7
-rw-r--r--src/zone.cc15
212 files changed, 9035 insertions, 7252 deletions
diff --git a/src/SConscript b/src/SConscript
index 453a7c6a..52607f15 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -111,8 +111,8 @@ SOURCES = {
runtime.cc
runtime-profiler.cc
safepoint-table.cc
- scanner-base.cc
scanner.cc
+ scanner-character-streams.cc
scopeinfo.cc
scopes.cc
serialize.cc
@@ -222,7 +222,7 @@ SOURCES = {
'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'],
'os:cygwin': ['platform-cygwin.cc', 'platform-posix.cc'],
'os:nullos': ['platform-nullos.cc'],
- 'os:win32': ['platform-win32.cc'],
+ 'os:win32': ['platform-win32.cc', 'win32-math.cc'],
'mode:release': [],
'mode:debug': [
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
@@ -233,15 +233,25 @@ SOURCES = {
PREPARSER_SOURCES = {
'all': Split("""
allocation.cc
+ bignum.cc
+ bignum-dtoa.cc
+ cached-powers.cc
+ conversions.cc
+ diy-fp.cc
+ dtoa.cc
+ fast-dtoa.cc
+ fixed-dtoa.cc
hashmap.cc
preparse-data.cc
preparser.cc
preparser-api.cc
- scanner-base.cc
+ scanner.cc
+ strtod.cc
token.cc
unicode.cc
utils.cc
- """)
+ """),
+ 'os:win32': ['win32-math.cc']
}
diff --git a/src/accessors.cc b/src/accessors.cc
index e7d6aa0e..951209d9 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -599,6 +599,7 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
if (!found_it) return isolate->heap()->undefined_value();
Handle<JSFunction> function(holder, isolate);
+ if (function->shared()->native()) return isolate->heap()->null_value();
// Find the top invocation of the function by traversing frames.
List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
@@ -709,6 +710,7 @@ class FrameFunctionIterator {
} while (next_function != NULL);
return false;
}
+
private:
void GetFunctions() {
functions_.Rewind(0);
@@ -732,6 +734,7 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return isolate->heap()->undefined_value();
+ if (holder->shared()->native()) return isolate->heap()->null_value();
Handle<JSFunction> function(holder, isolate);
FrameFunctionIterator it(isolate, no_alloc);
diff --git a/src/api.cc b/src/api.cc
index 5bda7253..479be5af 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -44,6 +44,7 @@
#include "platform.h"
#include "profile-generator-inl.h"
#include "runtime-profiler.h"
+#include "scanner-character-streams.h"
#include "serialize.h"
#include "snapshot.h"
#include "v8threads.h"
@@ -3265,6 +3266,42 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
namespace {
+static i::ElementsKind GetElementsKindFromExternalArrayType(
+ ExternalArrayType array_type) {
+ switch (array_type) {
+ case kExternalByteArray:
+ return i::EXTERNAL_BYTE_ELEMENTS;
+ break;
+ case kExternalUnsignedByteArray:
+ return i::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+ break;
+ case kExternalShortArray:
+ return i::EXTERNAL_SHORT_ELEMENTS;
+ break;
+ case kExternalUnsignedShortArray:
+ return i::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+ break;
+ case kExternalIntArray:
+ return i::EXTERNAL_INT_ELEMENTS;
+ break;
+ case kExternalUnsignedIntArray:
+ return i::EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ break;
+ case kExternalFloatArray:
+ return i::EXTERNAL_FLOAT_ELEMENTS;
+ break;
+ case kExternalDoubleArray:
+ return i::EXTERNAL_DOUBLE_ELEMENTS;
+ break;
+ case kExternalPixelArray:
+ return i::EXTERNAL_PIXEL_ELEMENTS;
+ break;
+ }
+ UNREACHABLE();
+ return i::DICTIONARY_ELEMENTS;
+}
+
+
void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
void* data,
ExternalArrayType array_type,
@@ -3283,9 +3320,9 @@ void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
elements->map() != isolate->heap()->MapForExternalArrayType(array_type);
if (cant_reuse_map) {
i::Handle<i::Map> external_array_map =
- isolate->factory()->GetExternalArrayElementsMap(
+ isolate->factory()->GetElementsTransitionMap(
i::Handle<i::Map>(object->map()),
- array_type,
+ GetElementsKindFromExternalArrayType(array_type),
object->HasFastProperties());
object->set_map(*external_array_map);
}
@@ -3347,6 +3384,7 @@ int v8::Object::GetIndexedPropertiesPixelDataLength() {
}
}
+
void v8::Object::SetIndexedPropertiesToExternalArrayData(
void* data,
ExternalArrayType array_type,
diff --git a/src/arguments.h b/src/arguments.h
index 72bbe1dd..e9a32702 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -75,6 +75,7 @@ class Arguments BASE_EMBEDDED {
int length() const { return length_; }
Object** arguments() { return arguments_; }
+
private:
int length_;
Object** arguments_;
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index a35380c1..60d2081c 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -1230,16 +1230,17 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
// r0: actual number of arguments
- Label non_function;
+ Label slow, non_function;
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ JumpIfSmi(r1, &non_function);
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
- __ b(ne, &non_function);
+ __ b(ne, &slow);
// 3a. Patch the first argument if necessary when calling a function.
// r0: actual number of arguments
// r1: function
Label shift_arguments;
+ __ mov(r4, Operand(0, RelocInfo::NONE)); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -1286,8 +1287,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ pop(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ LeaveInternalFrame();
- // Restore the function to r1.
+ // Restore the function to r1, and the flag to r4.
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+ __ mov(r4, Operand(0, RelocInfo::NONE));
__ jmp(&patch_receiver);
// Use the global receiver object from the called function as the
@@ -1307,23 +1309,30 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ jmp(&shift_arguments);
}
- // 3b. Patch the first argument when calling a non-function. The
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ mov(r4, Operand(1, RelocInfo::NONE)); // indicate function proxy
+ __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ b(eq, &shift_arguments);
+ __ bind(&non_function);
+ __ mov(r4, Operand(2, RelocInfo::NONE)); // indicate non-function
+
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
// r0: actual number of arguments
// r1: function
- __ bind(&non_function);
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r1, MemOperand(r2, -kPointerSize));
- // Clear r1 to indicate a non-function being called.
- __ mov(r1, Operand(0, RelocInfo::NONE));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
// the original first argument the new receiver.
// r0: actual number of arguments
// r1: function
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
__ bind(&shift_arguments);
{ Label loop;
// Calculate the copy start address (destination). Copy end address is sp.
@@ -1341,16 +1350,28 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ pop();
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
// r0: actual number of arguments
// r1: function
- { Label function;
- __ tst(r1, r1);
- __ b(ne, &function);
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
+ { Label function, non_proxy;
+ __ tst(r4, r4);
+ __ b(eq, &function);
// Expected number of arguments is 0 for CALL_NON_FUNCTION.
__ mov(r2, Operand(0, RelocInfo::NONE));
- __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(r5, CALL_AS_METHOD);
+ __ cmp(r4, Operand(1));
+ __ b(ne, &non_proxy);
+
+ __ push(r1); // re-add proxy object as additional argument
+ __ add(r0, r0, Operand(1));
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -1393,7 +1414,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -1418,18 +1439,24 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ mov(r1, Operand(0, RelocInfo::NONE)); // initial index
__ push(r1);
+ // Get the receiver.
+ __ ldr(r0, MemOperand(fp, kRecvOffset));
+
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
+ __ ldr(r1, MemOperand(fp, kFunctionOffset));
+ __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+ __ b(ne, &push_receiver);
+
// Change context eagerly to get the right global object if necessary.
- __ ldr(r0, MemOperand(fp, kFunctionOffset));
- __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
- // Load the shared function info while the function is still in r0.
- __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+ // Load the shared function info while the function is still in r1.
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
// Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
- __ ldr(r0, MemOperand(fp, kRecvOffset));
-
// Do not transform the receiver for strict mode functions.
- __ ldr(r2, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
+ Label call_to_object, use_global_receiver;
+ __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
__ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
kSmiTagSize)));
__ b(ne, &push_receiver);
@@ -1504,9 +1531,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ b(ne, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ ldr(r1, MemOperand(fp, kFunctionOffset));
+ __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+ __ b(ne, &call_proxy);
__ InvokeFunction(r1, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
@@ -1514,6 +1544,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize));
__ Jump(lr);
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(r1); // add function proxy as last argument
+ __ add(r0, r0, Operand(1));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ SetCallKind(r5, CALL_AS_METHOD);
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ add(sp, sp, Operand(3 * kPointerSize));
+ __ Jump(lr);
}
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 09d2c170..e65f6d9b 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -3432,7 +3432,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// Retrieve the pending exception and clear the variable.
__ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r3, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ ldr(r0, MemOperand(ip));
__ str(r3, MemOperand(ip));
@@ -3567,7 +3567,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ mov(r7, Operand(Smi::FromInt(marker)));
__ mov(r6, Operand(Smi::FromInt(marker)));
__ mov(r5,
- Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
+ Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
__ ldr(r5, MemOperand(r5));
__ Push(r8, r7, r6, r5);
@@ -3576,7 +3576,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// If this is the outermost JS call, set js_entry_sp value.
Label non_outermost_js;
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
__ mov(r5, Operand(ExternalReference(js_entry_sp)));
__ ldr(r6, MemOperand(r5));
__ cmp(r6, Operand::Zero());
@@ -3597,7 +3597,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// exception field in the JSEnv and return a failure sentinel.
// Coming in here the fp will be invalid because the PushTryHandler below
// sets it to 0 to signal the existence of the JSEntry frame.
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r0, MemOperand(ip));
__ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
@@ -3615,7 +3615,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Clear any pending exceptions.
__ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r5, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r5, MemOperand(ip));
@@ -3662,7 +3662,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Restore the top frame descriptors from the stack.
__ pop(r3);
__ mov(ip,
- Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
+ Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
__ str(r3, MemOperand(ip));
// Reset the stack to the callee saved registers.
@@ -4487,7 +4487,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// frame. Therefore we have to use fp, which points exactly to two pointer
// sizes below the previous sp. (Because creating a new stack frame pushes
// the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
- __ ldr(r0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+ __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
// If slice offset is not 0, load the length from the original sliced string.
// Argument 4, r3: End of string data
// Argument 3, r2: Start of string data
@@ -4495,7 +4495,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ add(r9, r8, Operand(r9, LSL, r3));
__ add(r2, r9, Operand(r1, LSL, r3));
- __ ldr(r8, FieldMemOperand(r0, String::kLengthOffset));
+ __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset));
__ mov(r8, Operand(r8, ASR, kSmiTagSize));
__ add(r3, r9, Operand(r8, LSL, r3));
@@ -4503,7 +4503,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Already there
// Argument 1 (r0): Subject string.
- // Already there
+ __ mov(r0, subject);
// Locate the code entry and call it.
__ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4520,12 +4520,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Check the result.
Label success;
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::SUCCESS));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS));
__ b(eq, &success);
Label failure;
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::FAILURE));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
__ b(eq, &failure);
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// If not exception it can only be retry. Handle that in the runtime system.
__ b(ne, &runtime);
// Result must now be exception. If there is no pending exception already a
@@ -4534,21 +4534,21 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
__ mov(r1, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r1, MemOperand(r1, 0));
- __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ ldr(r0, MemOperand(r2, 0));
- __ cmp(subject, r1);
+ __ cmp(r0, r1);
__ b(eq, &runtime);
__ str(r1, MemOperand(r2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
- __ LoadRoot(ip, Heap::kTerminationExceptionRootIndex);
- __ cmp(subject, ip);
+ __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
+
Label termination_exception;
__ b(eq, &termination_exception);
- __ Throw(subject); // Expects thrown value in r0.
+ __ Throw(r0); // Expects thrown value in r0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0.
@@ -4713,7 +4713,7 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -4739,7 +4739,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Check that the function is really a JavaScript function.
// r1: pushed function (to be verified)
- __ JumpIfSmi(r1, &slow);
+ __ JumpIfSmi(r1, &non_function);
// Get the map of the function object.
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
__ b(ne, &slow);
@@ -4767,8 +4767,23 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ b(ne, &non_function);
+ __ push(r1); // put proxy as additional argument
+ __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ SetCallKind(r5, CALL_AS_FUNCTION);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ Jump(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ str(r1, MemOperand(sp, argc_ * kPointerSize));
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
__ mov(r2, Operand(0, RelocInfo::NONE));
@@ -4894,7 +4909,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result_, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
@@ -5468,11 +5484,6 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Register to = r6;
Register from = r7;
- if (FLAG_string_slices) {
- __ nop(0); // Jumping as first instruction would crash the code generation.
- __ jmp(&runtime);
- }
-
__ Ldrd(to, from, MemOperand(sp, kToOffset));
STATIC_ASSERT(kFromOffset == kToOffset + 4);
STATIC_ASSERT(kSmiTag == 0);
@@ -5490,64 +5501,79 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ b(mi, &runtime); // Fail if from > to.
// Special handling of sub-strings of length 1 and 2. One character strings
// are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache.
+ // cache). Two character strings are looked for in the symbol cache in
+ // generated code.
__ cmp(r2, Operand(2));
__ b(lt, &runtime);
- // r2: length
- // r3: from index (untaged smi)
+ // r2: result string length
+ // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
-
// Make sure first argument is a sequential (or flat) string.
- __ ldr(r5, MemOperand(sp, kStringOffset));
+ __ ldr(r0, MemOperand(sp, kStringOffset));
STATIC_ASSERT(kSmiTag == 0);
- __ JumpIfSmi(r5, &runtime);
- Condition is_string = masm->IsObjectStringType(r5, r1);
+ __ JumpIfSmi(r0, &runtime);
+ Condition is_string = masm->IsObjectStringType(r0, r1);
__ b(NegateCondition(is_string), &runtime);
+ // Short-cut for the case of trivial substring.
+ Label return_r0;
+ // r0: original string
+ // r2: result string length
+ __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
+ __ cmp(r2, Operand(r4, ASR, 1));
+ __ b(eq, &return_r0);
+
+ Label create_slice;
+ if (FLAG_string_slices) {
+ __ cmp(r2, Operand(SlicedString::kMinLength));
+ __ b(ge, &create_slice);
+ }
+
+ // r0: original string
// r1: instance type
- // r2: length
+ // r2: result string length
// r3: from index (untagged smi)
- // r5: string
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
Label seq_string;
__ and_(r4, r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
__ cmp(r4, Operand(kConsStringTag));
- __ b(gt, &runtime); // External strings go to runtime.
+ __ b(gt, &runtime); // Slices and external strings go to runtime.
__ b(lt, &seq_string); // Sequential strings are handled directly.
// Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened
// cons strings, but not much).
- __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset));
- __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
+ __ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset));
+ __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset));
__ tst(r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag == 0);
- __ b(ne, &runtime); // Cons and External strings go to runtime.
+ __ b(ne, &runtime); // Cons, slices and external strings go to runtime.
// Definitly a sequential string.
__ bind(&seq_string);
- // r1: instance type.
- // r2: length
- // r3: from index (untaged smi)
- // r5: string
+ // r0: original string
+ // r1: instance type
+ // r2: result string length
+ // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
- __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset));
+ __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
__ cmp(r4, Operand(to));
__ b(lt, &runtime); // Fail if to > length.
to = no_reg;
- // r1: instance type.
- // r2: result string length.
- // r3: from index (untaged smi)
- // r5: string.
+ // r0: original string or left hand side of the original cons string.
+ // r1: instance type
+ // r2: result string length
+ // r3: from index (untagged smi)
// r7 (a.k.a. from): from offset (smi)
// Check for flat ASCII string.
Label non_ascii_flat;
@@ -5561,82 +5587,146 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Sub string of length 2 requested.
// Get the two characters forming the sub string.
- __ add(r5, r5, Operand(r3));
- __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize));
- __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1));
+ __ add(r0, r0, Operand(r3));
+ __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
+ __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table.
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
// r2: result string length.
// r3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string);
__ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
__ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
__ bind(&result_longer_than_two);
+ // Locate 'from' character of string.
+ __ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ __ add(r5, r5, Operand(from, ASR, 1));
+
// Allocate the result.
__ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
- // r0: result string.
- // r2: result string length.
- // r5: string.
+ // r0: result string
+ // r2: result string length
+ // r5: first character of substring to copy
// r7 (a.k.a. from): from offset (smi)
// Locate first character of result.
__ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- __ add(r5, r5, Operand(from, ASR, 1));
- // r0: result string.
- // r1: first character of result string.
- // r2: result string length.
- // r5: first character of sub string to copy.
+ // r0: result string
+ // r1: first character of result string
+ // r2: result string length
+ // r5: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
__ bind(&non_ascii_flat);
- // r2: result string length.
- // r5: string.
+ // r0: original string
+ // r2: result string length
// r7 (a.k.a. from): from offset (smi)
// Check for flat two byte string.
+ // Locate 'from' character of string.
+ __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ // As "from" is a smi it is 2 times the value which matches the size of a two
+ // byte character.
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ add(r5, r5, Operand(from));
+
// Allocate the result.
__ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
- // r0: result string.
- // r2: result string length.
- // r5: string.
+ // r0: result string
+ // r2: result string length
+ // r5: first character of substring to copy
// Locate first character of result.
__ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // As "from" is a smi it is 2 times the value which matches the size of a two
- // byte character.
- __ add(r5, r5, Operand(from));
+
from = no_reg;
// r0: result string.
// r1: first character of result.
// r2: result length.
- // r5: first character of string to copy.
+ // r5: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
+ __ jmp(&return_r0);
+
+ if (FLAG_string_slices) {
+ __ bind(&create_slice);
+ // r0: original string
+ // r1: instance type
+ // r2: length
+ // r3: from index (untagged smi)
+ // r6 (a.k.a. to): to (smi)
+ // r7 (a.k.a. from): from offset (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ tst(r1, Operand(kStringRepresentationMask));
+ __ b(eq, &seq_string);
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ tst(r1, Operand(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ b(eq, &runtime);
+
+ __ tst(r1, Operand(kSlicedNotConsMask));
+ __ b(ne, &sliced_string);
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
+ __ LoadRoot(r9, Heap::kEmptyStringRootIndex);
+ __ cmp(r5, r9);
+ __ b(ne, &runtime);
+ __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset));
+ __ add(r7, r7, r5);
+ __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ mov(r5, r0);
+
+ __ bind(&allocate_slice);
+ // r1: instance type of original string
+ // r2: length
+ // r5: underlying subject string
+ // r7 (a.k.a. from): from offset (smi)
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ tst(r1, Operand(kStringEncodingMask));
+ __ b(eq, &two_byte_slice);
+ __ AllocateAsciiSlicedString(r0, r2, r3, r4, &runtime);
+ __ jmp(&set_slice_header);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(r0, r2, r3, r4, &runtime);
+ __ bind(&set_slice_header);
+ __ str(r7, FieldMemOperand(r0, SlicedString::kOffsetOffset));
+ __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
+ }
+
+ __ bind(&return_r0);
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 1604883b..50ed8b1d 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -193,14 +193,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ mov(r1, Operand(Context::SlotOffset(slot->index())));
+ __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
@@ -244,7 +244,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), r0, r1, r2);
+ SetVar(arguments, r0, r1, r2);
}
if (FLAG_trace) {
@@ -258,17 +258,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
@@ -367,24 +369,28 @@ void FullCodeGenerator::EmitReturnSequence() {
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
__ push(result_register());
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -616,45 +622,54 @@ void FullCodeGenerator::Split(Condition cond,
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return MemOperand(fp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return MemOperand(r0, 0);
+ return MemOperand(fp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
+}
+
+
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
// Use destination as scratch.
- MemOperand slot_operand = EmitSlotSearch(source, destination);
- __ ldr(destination, slot_operand);
+ MemOperand location = VarOperand(var, dest);
+ __ ldr(dest, location);
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ str(src, location);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- __ RecordWrite(scratch1,
- Operand(Context::SlotOffset(dst->index())),
- scratch2,
+ if (var->IsContextSlot()) {
+ __ RecordWrite(scratch0,
+ Operand(Context::SlotOffset(var->index())),
+ scratch1,
src);
}
}
@@ -687,29 +702,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
+ __ str(result_register(), StackOperand(variable));
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ str(ip, MemOperand(fp, SlotOffset(slot)));
+ __ str(ip, StackOperand(variable));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -722,22 +741,27 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ Check(ne, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ str(result_register(), ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
+ __ str(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
// We know that we have written a function, which is not a smi.
__ mov(r1, Operand(cp));
__ RecordWrite(r1, Operand(offset), r2, result_register());
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ str(ip, ContextOperand(cp, slot->index()));
+ __ str(ip, ContextOperand(cp, variable->index()));
// No write barrier since the_hole_value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ mov(r2, Operand(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -755,7 +779,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
__ Push(cp, r2, r1, r0);
} else {
- __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
+ __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
__ Push(cp, r2, r1, r0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -765,19 +789,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
- __ mov(r2, Operand(pairs));
- __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r2, r1, r0);
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ mov(r1, Operand(pairs));
+ __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
+ __ Push(cp, r1, r0);
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1085,10 +1106,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register current = cp;
Register next = r1;
Register temp = r2;
@@ -1135,7 +1155,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
__ ldr(r0, GlobalObjectOperand());
- __ mov(r2, Operand(slot->var()->name()));
+ __ mov(r2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1144,15 +1164,14 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = cp;
Register next = r3;
Register temp = r4;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1173,59 +1192,30 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to
// return an cp-based operand (the write barrier cannot be allowed to
// destroy the cp register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ ldr(r1,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ mov(r0, Operand(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
}
+ __ jmp(done);
}
}
@@ -1235,66 +1225,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in r2 and the global
- // object (receiver) in r0.
- __ ldr(r0, GlobalObjectOperand());
- __ mov(r2, Operand(var->name()));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(r0);
-
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ mov(r1, Operand(var->name()));
- __ Push(cp, r1); // Context and name.
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in r2 and the global
+ // object (receiver) in r0.
+ __ ldr(r0, GlobalObjectOperand());
+ __ mov(r2, Operand(var->name()));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(r0);
+ break;
+ }
- context()->Plug(r0);
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ GetVar(r0, var);
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ if (var->mode() == Variable::LET) {
+ Label done;
+ __ b(ne, &done);
+ __ mov(r0, Operand(var->name()));
+ __ push(r0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&done);
+ } else {
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+ }
+ context()->Plug(r0);
+ }
+ break;
+ }
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- MemOperand slot_operand = EmitSlotSearch(slot, r0);
- __ ldr(r0, slot_operand);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- context()->Plug(r0);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, r0);
- __ ldr(r0, slot_operand);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ b(ne, &done);
- __ mov(r0, Operand(var->name()));
- __ push(r0);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ mov(r1, Operand(var->name()));
+ __ Push(cp, r1); // Context and name.
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(r0);
- } else {
- context()->Plug(slot);
}
}
}
@@ -1828,14 +1812,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in r0, variable name in
- // r2, and the global object in r1.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
@@ -1844,120 +1822,83 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- // Detect const reinitialization by checking for the hole value.
- __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r1, ip);
- __ b(ne, &skip);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(r0);
- __ mov(r0, Operand(slot->var()->name()));
- __ Push(cp, r0); // Context and name.
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ ldr(r1, StackOperand(var));
+ __ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &skip);
+ __ str(result_register(), StackOperand(var));
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(r0);
+ __ mov(r0, Operand(var->name()));
+ __ Push(cp, r0); // Context and name.
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r1, ip);
- __ b(ne, &assign);
- __ mov(r1, Operand(var->name()));
- __ push(r1);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- }
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, r1);
- // Check for an initialized let binding.
- __ ldr(r3, target);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r3, ip);
- __ b(ne, &assign);
- __ mov(r3, Operand(var->name()));
- __ push(r3);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ str(result_register(), target);
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(r0); // Value.
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, r1, r0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, r1);
+ __ ldr(r3, location);
+ __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &assign);
+ __ mov(r3, Operand(var->name()));
+ __ push(r3);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ bind(&assign);
+ __ str(result_register(), location);
+ if (var->IsContextSlot()) {
// RecordWrite may destroy all its register arguments.
__ mov(r3, result_register());
- int offset = Context::SlotOffset(slot->index());
+ int offset = Context::SlotOffset(var->index());
__ RecordWrite(r1, Operand(offset), r2, r3);
- break;
}
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(r0); // Value.
- __ mov(r1, Operand(slot->var()->name()));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r1, r0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
} else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
-
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, r1);
- // Perform the assignment and issue the write barrier.
- __ str(result_register(), target);
- // RecordWrite may destroy all its register arguments.
- __ mov(r3, result_register());
- int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
- __ RecordWrite(r1, Operand(offset), r2, r3);
- break;
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, r1);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ ldr(r2, location);
+ __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
+ __ Check(eq, "Let binding re-initialization.");
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(r0); // Value.
- __ mov(r1, Operand(slot->var()->name()));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r1, r0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ // Perform the assignment.
+ __ str(r0, location);
+ if (var->IsContextSlot()) {
+ __ mov(r3, r0);
+ __ RecordWrite(r1, Operand(Context::SlotOffset(var->index())), r2, r3);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(r0); // Value.
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, r1, r0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2087,9 +2028,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2120,9 +2060,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
__ Call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2143,8 +2082,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2167,8 +2105,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
int receiver_offset = 2 + info_->scope()->num_parameters();
__ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(r1);
- // Push the strict mode flag.
- __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ mov(r1, Operand(Smi::FromInt(strict_mode)));
__ push(r1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@@ -2185,10 +2128,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
@@ -2197,7 +2141,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
@@ -2211,11 +2155,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(r0);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2223,14 +2166,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1);
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values.
@@ -2240,37 +2181,32 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, r0);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ ldr(r0, GlobalObjectOperand());
__ push(r0);
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx).
__ push(context_register());
- __ mov(r2, Operand(var->name()));
+ __ mov(r2, Operand(proxy->name()));
__ push(r2);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ Push(r0, r1); // Function, receiver.
@@ -2295,26 +2231,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ ldr(r1, GlobalObjectOperand());
@@ -2579,7 +2510,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
&if_true, &if_false, &fall_through);
__ JumpIfSmi(r0, if_false);
- __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
+ __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Split(eq, if_true, if_false, fall_through);
@@ -3618,9 +3549,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
__ mov(r2, Operand(expr->name()));
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count,
- NOT_IN_LOOP,
- mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3636,32 +3565,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
__ push(r1);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name()));
__ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(r2, r1, r0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
// Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects.
- context()->Plug(false);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3936,7 +3865,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name()));
@@ -3946,15 +3875,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ Call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(r0);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ mov(r0, Operand(proxy->name()));
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 6bad5ac0..2e49cae9 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -146,7 +146,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ b(ne, miss);
// Get the value at the masked, scaled index and return.
@@ -194,9 +194,9 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
const int kElementsStartOffset = StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ tst(scratch1, Operand(kTypeAndReadOnlyMask));
__ b(ne, miss);
@@ -393,7 +393,6 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -734,9 +733,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r0, r2, r3, r4, r5);
@@ -1380,10 +1378,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r1, r2, r3, r4, r5);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 6292ff85..30ccd05b 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -311,13 +311,13 @@ void LCallKeyed::PrintDataTo(StringStream* stream) {
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -546,7 +546,8 @@ LChunk* LChunkBuilder::Build() {
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -710,9 +711,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -995,13 +994,10 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1011,6 +1007,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1019,7 +1016,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1864,15 +1861,15 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1881,7 +1878,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
AssignEnvironment(load_instr) : load_instr;
}
@@ -1932,21 +1929,21 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS;
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index e14e6fc7..8c18760f 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -1158,7 +1158,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1662,7 +1662,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2159,8 +2159,7 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 976576be..f5d74491 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -101,7 +101,8 @@ void LCodeGen::FinishCode(Handle<Code> code) {
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -198,14 +199,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ mov(r1, Operand(Context::SlotOffset(slot->index())));
+ __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
@@ -2410,11 +2411,11 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
__ ubfx(scratch, scratch, Map::kElementsKindShift,
Map::kElementsKindBitCount);
- __ cmp(scratch, Operand(JSObject::FAST_ELEMENTS));
+ __ cmp(scratch, Operand(FAST_ELEMENTS));
__ b(eq, &done);
- __ cmp(scratch, Operand(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(lt, &fail);
- __ cmp(scratch, Operand(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(le, &done);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
@@ -2478,7 +2479,7 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Register scratch = scratch0();
int shift_size =
- ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
int constant_key = 0;
if (key_is_constant) {
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
@@ -2515,7 +2516,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = no_reg;
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
if (key_is_constant) {
@@ -2528,18 +2529,18 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
}
int shift_size = ElementsKindToShiftSize(elements_kind);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size))
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vldr(result.low(), scratch0(), 0);
__ vcvt_f64_f32(result, result.low());
- } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vldr(result, scratch0(), 0);
}
} else {
@@ -2548,23 +2549,23 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(result, mem_operand);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ ldrb(result, mem_operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ ldrsh(result, mem_operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ ldrh(result, mem_operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ ldr(result, mem_operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ ldr(result, mem_operand);
__ cmp(result, Operand(0x80000000));
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2572,12 +2573,12 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(cs, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3177,7 +3178,7 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
int arity = instr->arity();
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -3189,7 +3190,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr);
// Restore context register.
@@ -3201,7 +3202,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ Drop(1);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3214,7 +3215,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3340,7 +3341,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
} else {
key = ToRegister(instr->key());
}
- int shift_size = ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
@@ -3367,7 +3368,7 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
Register external_pointer = ToRegister(instr->external_pointer());
Register key = no_reg;
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
if (key_is_constant) {
@@ -3380,17 +3381,17 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
}
int shift_size = ElementsKindToShiftSize(elements_kind);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
: Operand(key, LSL, shift_size));
__ add(scratch0(), external_pointer, operand);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
__ vstr(double_scratch0().low(), scratch0(), 0);
- } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vstr(value, scratch0(), 0);
}
} else {
@@ -3399,25 +3400,25 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(value, mem_operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(value, mem_operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(value, mem_operand);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3509,7 +3510,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
diff --git a/src/arm/lithium-gap-resolver-arm.h b/src/arm/lithium-gap-resolver-arm.h
index 334d2920..9dd09c8d 100644
--- a/src/arm/lithium-gap-resolver-arm.h
+++ b/src/arm/lithium-gap-resolver-arm.h
@@ -40,7 +40,6 @@ class LGapResolver;
class LGapResolver BASE_EMBEDDED {
public:
-
explicit LGapResolver(LCodeGen* owner);
// Resolve a set of parallel moves, emitting assembler instructions.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 88477bb7..f37f3102 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -760,9 +760,9 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
- mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
str(fp, MemOperand(ip));
- mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
str(cp, MemOperand(ip));
// Optionally save all double registers.
@@ -838,11 +838,11 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
// Clear top frame.
mov(r3, Operand(0, RelocInfo::NONE));
- mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
str(r3, MemOperand(ip));
// Restore current context from top and clear it in debug mode.
- mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
ldr(cp, MemOperand(ip));
#ifdef DEBUG
str(r3, MemOperand(ip));
@@ -1118,7 +1118,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
}
stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(r1, MemOperand(r3));
push(r1);
// Link this handler as the new current one.
@@ -1134,7 +1134,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
mov(r7, Operand(0, RelocInfo::NONE)); // NULL frame pointer.
stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(r6, MemOperand(r7));
push(r6);
// Link this handler as the new current one.
@@ -1146,7 +1146,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r1);
- mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
str(r1, MemOperand(ip));
}
@@ -1166,7 +1166,7 @@ void MacroAssembler::Throw(Register value) {
}
// Drop the sp to the top of the handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(sp, MemOperand(r3));
// Restore the next handler.
@@ -1206,7 +1206,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
}
// Drop sp to the top stack handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(sp, MemOperand(r3));
// Unwind the handlers until the ENTRY handler is found.
@@ -1230,7 +1230,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
mov(r0, Operand(false, RelocInfo::NONE));
mov(r2, Operand(external_caught));
str(r0, MemOperand(r2));
@@ -1238,7 +1238,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate())));
str(r0, MemOperand(r2));
}
@@ -1421,7 +1421,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ldr(t1, FieldMemOperand(t2, kDetailsOffset));
- tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
+ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
b(ne, miss);
// Get the value at the masked, scaled index and return.
@@ -1725,6 +1725,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
void MacroAssembler::CompareObjectType(Register object,
Register map,
Register type_reg,
@@ -1753,7 +1793,7 @@ void MacroAssembler::CompareRoot(Register obj,
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
b(hi, fail);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 9c653adb..6084fde2 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -532,6 +532,16 @@ class MacroAssembler: public Assembler {
Register scratch1,
Register scratch2,
Label* gc_required);
+ void AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
// Allocates a heap number or jumps to the gc_required label if the young
// space is full and a scavenge is needed. All registers are clobbered also
@@ -586,9 +596,7 @@ class MacroAssembler: public Assembler {
// Compare instance type in a map. map contains a valid map object whose
// object type should be compared with the given type. This both
- // sets the flags and leaves the object type in the type_reg register. It
- // leaves the heap object in the heap_object register unless the heap_object
- // register is the same register as type_reg.
+ // sets the flags and leaves the object type in the type_reg register.
void CompareInstanceType(Register map,
Register type_reg,
InstanceType type);
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index 0e653868..5c8ed069 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -116,6 +116,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
static int CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame);
+
private:
// Offsets from frame_pointer() of function parameters and stored registers.
static const int kFramePointer = 0;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 53458929..f8565924 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -3099,7 +3099,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
// -- r1 : receiver
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(r1,
@@ -3193,7 +3193,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
// -- r3 : scratch
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -3438,25 +3438,25 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
}
-static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
+static bool IsElementTypeSigned(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
return true;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
return false;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
return false;
}
@@ -3466,7 +3466,7 @@ static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@@ -3501,24 +3501,24 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
Register value = r2;
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(value, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ ldrb(value, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ ldrsh(value, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ ldrh(value, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ ldr(value, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ add(r2, r3, Operand(key, LSL, 1));
@@ -3527,7 +3527,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ ldr(value, MemOperand(r3, key, LSL, 1));
}
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ add(r2, r3, Operand(key, LSL, 2));
@@ -3539,10 +3539,10 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ ldr(r3, MemOperand(r4, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3556,7 +3556,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// d0: value (if VFP3 is supported)
// r2/r3: value (if VFP3 is not supported)
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3600,7 +3600,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3665,7 +3665,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ mov(r0, r4);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
if (CpuFeatures::IsSupported(VFP3)) {
@@ -3735,7 +3735,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ mov(r0, r3);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Allocate a HeapNumber for the result. Don't use r0 and r1 as
@@ -3792,7 +3792,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@@ -3824,7 +3824,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
// r3: external array.
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
} else {
@@ -3836,29 +3836,29 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// r3: base pointer of external storage.
// r5: value (integer).
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
// Clamp the value to [0..255].
__ Usat(r5, 8, Operand(r5));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(r4, key);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ add(r3, r3, Operand(key, LSL, 2));
// r3: effective address of the double element
FloatingPointHelper::Destination destination;
@@ -3879,10 +3879,10 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ str(r7, MemOperand(r3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3890,7 +3890,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Entry registers are intact, r0 holds the value which is the return value.
__ Ret();
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
// r3: external array.
__ bind(&check_heap_number);
__ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
@@ -3906,7 +3906,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// vldr requires offset to be a multiple of 4 so we can not
// include -kHeapObjectTag into it.
__ sub(r5, r0, Operand(kHeapObjectTag));
@@ -3914,7 +3914,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ add(r5, r3, Operand(key, LSL, 1));
__ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(key, LSL, 2));
@@ -3927,25 +3927,25 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ EmitECMATruncate(r5, d0, s2, r6, r7, r9);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3959,7 +3959,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
__ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Label done, nan_or_infinity_or_zero;
static const int kMantissaInHiWordShift =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
@@ -4011,7 +4011,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ add(r7, r3, Operand(key, LSL, 2));
// r7: effective address of destination element.
__ str(r6, MemOperand(r7, 0));
@@ -4066,25 +4066,25 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ bind(&done);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/array.js b/src/array.js
index f73b0c1b..98fe3ac7 100644
--- a/src/array.js
+++ b/src/array.js
@@ -208,7 +208,7 @@ function ConvertToLocaleString(e) {
// Call ToString if toLocaleString is not a function.
// See issue 877615.
var e_obj = ToObject(e);
- if (IS_FUNCTION(e_obj.toLocaleString))
+ if (IS_SPEC_FUNCTION(e_obj.toLocaleString))
return ToString(e_obj.toLocaleString());
else
return ToString(e);
@@ -730,7 +730,7 @@ function ArraySort(comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.
- if (!IS_FUNCTION(comparefn)) {
+ if (!IS_SPEC_FUNCTION(comparefn)) {
comparefn = function (x, y) {
if (x === y) return 0;
if (%_IsSmi(x) && %_IsSmi(y)) {
@@ -993,7 +993,7 @@ function ArrayFilter(f, receiver) {
["Array.prototype.filter"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1022,7 +1022,7 @@ function ArrayForEach(f, receiver) {
["Array.prototype.forEach"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1048,7 +1048,7 @@ function ArraySome(f, receiver) {
["Array.prototype.some"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1073,7 +1073,7 @@ function ArrayEvery(f, receiver) {
["Array.prototype.every"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1097,7 +1097,7 @@ function ArrayMap(f, receiver) {
["Array.prototype.map"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1245,7 +1245,7 @@ function ArrayReduce(callback, current) {
["Array.prototype.reduce"]);
}
- if (!IS_FUNCTION(callback)) {
+ if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
@@ -1281,7 +1281,7 @@ function ArrayReduceRight(callback, current) {
["Array.prototype.reduceRight"]);
}
- if (!IS_FUNCTION(callback)) {
+ if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
var i = ToUint32(this.length) - 1;
@@ -1314,12 +1314,13 @@ function ArrayIsArray(obj) {
// -------------------------------------------------------------------
-function SetupArray() {
- // Setup non-enumerable constructor property on the Array.prototype
+function SetUpArray() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable constructor property on the Array.prototype
// object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
- // Setup non-enumerable functions on the Array object.
+ // Set up non-enumerable functions on the Array object.
InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray
));
@@ -1337,7 +1338,7 @@ function SetupArray() {
return f;
}
- // Setup non-enumerable functions of the Array.prototype object and
+ // Set up non-enumerable functions of the Array.prototype object and
// set their names.
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
@@ -1368,19 +1369,13 @@ function SetupArray() {
%FinishArrayPrototypeSetup($Array.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never
- // exposed to user code, so no hidden prototypes or DONT_ENUM attributes
- // are necessary.
- // The null __proto__ ensures that we never inherit any user created
- // getters or setters from, e.g., Object.prototype.
- InternalArray.prototype.__proto__ = null;
- // Adding only the functions that are actually used, and a toString.
- InternalArray.prototype.join = getFunction("join", ArrayJoin);
- InternalArray.prototype.pop = getFunction("pop", ArrayPop);
- InternalArray.prototype.push = getFunction("push", ArrayPush);
- InternalArray.prototype.toString = function() {
- return "Internal Array, length " + this.length;
- };
+ // exposed to user code.
+ // Adding only the functions that are actually used.
+ SetUpLockedPrototype(InternalArray, $Array(), $Array(
+ "join", getFunction("join", ArrayJoin),
+ "pop", getFunction("pop", ArrayPop),
+ "push", getFunction("push", ArrayPush)
+ ));
}
-
-SetupArray();
+SetUpArray();
diff --git a/src/ast.cc b/src/ast.cc
index 7319abe6..418cc432 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -36,20 +36,9 @@
namespace v8 {
namespace internal {
-AstSentinels::AstSentinels()
- : this_proxy_(Isolate::Current(), true),
- identifier_proxy_(Isolate::Current(), false),
- valid_left_hand_side_sentinel_(Isolate::Current()),
- this_property_(Isolate::Current(), &this_proxy_, NULL, 0),
- call_sentinel_(Isolate::Current(), NULL, NULL, 0) {
-}
-
-
// ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type.
-void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); }
-
#define DECL_ACCEPT(type) \
void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT)
@@ -101,15 +90,6 @@ VariableProxy::VariableProxy(Isolate* isolate,
}
-VariableProxy::VariableProxy(Isolate* isolate, bool is_this)
- : Expression(isolate),
- var_(NULL),
- is_this_(is_this),
- inside_with_(false),
- is_trivial_(false) {
-}
-
-
void VariableProxy::BindTo(Variable* var) {
ASSERT(var_ == NULL); // must be bound only once
ASSERT(var != NULL); // must bind
@@ -414,12 +394,6 @@ bool TargetCollector::IsInlineable() const {
}
-bool Slot::IsInlineable() const {
- UNREACHABLE();
- return false;
-}
-
-
bool ForInStatement::IsInlineable() const {
return false;
}
@@ -430,11 +404,6 @@ bool WithStatement::IsInlineable() const {
}
-bool ExitContextStatement::IsInlineable() const {
- return false;
-}
-
-
bool SwitchStatement::IsInlineable() const {
return false;
}
@@ -487,12 +456,6 @@ bool SharedFunctionInfoLiteral::IsInlineable() const {
}
-bool ValidLeftHandSideSentinel::IsInlineable() const {
- UNREACHABLE();
- return false;
-}
-
-
bool ForStatement::IsInlineable() const {
return (init() == NULL || init()->IsInlineable())
&& (cond() == NULL || cond()->IsInlineable())
@@ -566,7 +529,7 @@ bool Conditional::IsInlineable() const {
bool VariableProxy::IsInlineable() const {
- return var()->is_global() || var()->IsStackAllocated();
+ return var()->IsUnallocated() || var()->IsStackAllocated();
}
@@ -1006,7 +969,7 @@ class RegExpUnparser: public RegExpVisitor {
public:
RegExpUnparser();
void VisitCharacterRange(CharacterRange that);
- SmartPointer<const char> ToString() { return stream_.ToCString(); }
+ SmartArrayPointer<const char> ToString() { return stream_.ToCString(); }
#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
#undef MAKE_CASE
@@ -1161,7 +1124,7 @@ void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
}
-SmartPointer<const char> RegExpTree::ToString() {
+SmartArrayPointer<const char> RegExpTree::ToString() {
RegExpUnparser unparser;
Accept(&unparser, NULL);
return unparser.ToString();
diff --git a/src/ast.h b/src/ast.h
index 74182d5d..b56205f9 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -62,7 +62,6 @@ namespace internal {
V(BreakStatement) \
V(ReturnStatement) \
V(WithStatement) \
- V(ExitContextStatement) \
V(SwitchStatement) \
V(DoWhileStatement) \
V(WhileStatement) \
@@ -134,6 +133,10 @@ class AstNode: public ZoneObject {
static const int kNoNumber = -1;
static const int kFunctionEntryId = 2; // Using 0 could disguise errors.
+ // This AST id identifies the point after the declarations have been
+ // visited. We need it to capture the environment effects of declarations
+ // that emit code (function declarations).
+ static const int kDeclarationsId = 3;
// Override ZoneObject's new to count allocated AST nodes.
void* operator new(size_t size, Zone* zone) {
@@ -161,7 +164,6 @@ class AstNode: public ZoneObject {
virtual BreakableStatement* AsBreakableStatement() { return NULL; }
virtual IterationStatement* AsIterationStatement() { return NULL; }
virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
- virtual Slot* AsSlot() { return NULL; }
// True if the node is simple enough for us to inline calls containing it.
virtual bool IsInlineable() const = 0;
@@ -316,20 +318,6 @@ class Expression: public AstNode {
};
-/**
- * A sentinel used during pre parsing that represents some expression
- * that is a valid left hand side without having to actually build
- * the expression.
- */
-class ValidLeftHandSideSentinel: public Expression {
- public:
- explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {}
- virtual bool IsValidLeftHandSide() { return true; }
- virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
- virtual bool IsInlineable() const;
-};
-
-
class BreakableStatement: public Statement {
public:
enum Type {
@@ -404,10 +392,14 @@ class Block: public BreakableStatement {
class Declaration: public AstNode {
public:
- Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun)
+ Declaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* fun,
+ Scope* scope)
: proxy_(proxy),
mode_(mode),
- fun_(fun) {
+ fun_(fun),
+ scope_(scope) {
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -421,11 +413,15 @@ class Declaration: public AstNode {
Variable::Mode mode() const { return mode_; }
FunctionLiteral* fun() const { return fun_; } // may be NULL
virtual bool IsInlineable() const;
+ Scope* scope() const { return scope_; }
private:
VariableProxy* proxy_;
Variable::Mode mode_;
FunctionLiteral* fun_;
+
+ // Nested scope from which the declaration originated.
+ Scope* scope_;
};
@@ -684,14 +680,6 @@ class WithStatement: public Statement {
};
-class ExitContextStatement: public Statement {
- public:
- virtual bool IsInlineable() const;
-
- DECLARE_NODE_TYPE(ExitContextStatement)
-};
-
-
class CaseClause: public ZoneObject {
public:
CaseClause(Isolate* isolate,
@@ -1114,9 +1102,6 @@ class VariableProxy: public Expression {
DECLARE_NODE_TYPE(VariableProxy)
- // Type testing & conversion
- Variable* AsVariable() { return (this == NULL) ? NULL : var_; }
-
virtual bool IsValidLeftHandSide() {
return var_ == NULL ? true : var_->IsValidLeftHandSide();
}
@@ -1133,10 +1118,7 @@ class VariableProxy: public Expression {
return !is_this() && name().is_identical_to(n);
}
- bool IsArguments() {
- Variable* variable = AsVariable();
- return (variable == NULL) ? false : variable->is_arguments();
- }
+ bool IsArguments() { return var_ != NULL && var_->is_arguments(); }
Handle<String> name() const { return name_; }
Variable* var() const { return var_; }
@@ -1162,73 +1144,11 @@ class VariableProxy: public Expression {
bool is_this,
bool inside_with,
int position = RelocInfo::kNoPosition);
- VariableProxy(Isolate* isolate, bool is_this);
friend class Scope;
};
-class VariableProxySentinel: public VariableProxy {
- public:
- virtual bool IsValidLeftHandSide() { return !is_this(); }
-
- private:
- VariableProxySentinel(Isolate* isolate, bool is_this)
- : VariableProxy(isolate, is_this) { }
-
- friend class AstSentinels;
-};
-
-
-class Slot: public Expression {
- public:
- enum Type {
- // A slot in the parameter section on the stack. index() is
- // the parameter index, counting left-to-right, starting at 0.
- PARAMETER,
-
- // A slot in the local section on the stack. index() is
- // the variable index in the stack frame, starting at 0.
- LOCAL,
-
- // An indexed slot in a heap context. index() is the
- // variable index in the context object on the heap,
- // starting at 0. var()->scope() is the corresponding
- // scope.
- CONTEXT,
-
- // A named slot in a heap context. var()->name() is the
- // variable name in the context object on the heap,
- // with lookup starting at the current context. index()
- // is invalid.
- LOOKUP
- };
-
- Slot(Isolate* isolate, Variable* var, Type type, int index)
- : Expression(isolate), var_(var), type_(type), index_(index) {
- ASSERT(var != NULL);
- }
-
- virtual void Accept(AstVisitor* v);
-
- virtual Slot* AsSlot() { return this; }
-
- bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
-
- // Accessors
- Variable* var() const { return var_; }
- Type type() const { return type_; }
- int index() const { return index_; }
- bool is_arguments() const { return var_->is_arguments(); }
- virtual bool IsInlineable() const;
-
- private:
- Variable* var_;
- Type type_;
- int index_;
-};
-
-
class Property: public Expression {
public:
Property(Isolate* isolate,
@@ -1337,36 +1257,6 @@ class Call: public Expression {
};
-class AstSentinels {
- public:
- ~AstSentinels() { }
-
- // Returns a property singleton property access on 'this'. Used
- // during preparsing.
- Property* this_property() { return &this_property_; }
- VariableProxySentinel* this_proxy() { return &this_proxy_; }
- VariableProxySentinel* identifier_proxy() { return &identifier_proxy_; }
- ValidLeftHandSideSentinel* valid_left_hand_side_sentinel() {
- return &valid_left_hand_side_sentinel_;
- }
- Call* call_sentinel() { return &call_sentinel_; }
- EmptyStatement* empty_statement() { return &empty_statement_; }
-
- private:
- AstSentinels();
- VariableProxySentinel this_proxy_;
- VariableProxySentinel identifier_proxy_;
- ValidLeftHandSideSentinel valid_left_hand_side_sentinel_;
- Property this_property_;
- Call call_sentinel_;
- EmptyStatement empty_statement_;
-
- friend class Isolate;
-
- DISALLOW_COPY_AND_ASSIGN(AstSentinels);
-};
-
-
class CallNew: public Expression {
public:
CallNew(Isolate* isolate,
@@ -1885,7 +1775,7 @@ class RegExpTree: public ZoneObject {
// expression.
virtual Interval CaptureRegisters() { return Interval::Empty(); }
virtual void AppendToText(RegExpText* text);
- SmartPointer<const char> ToString();
+ SmartArrayPointer<const char> ToString();
#define MAKE_ASTYPE(Name) \
virtual RegExp##Name* As##Name(); \
virtual bool Is##Name();
@@ -2239,9 +2129,6 @@ class AstVisitor BASE_EMBEDDED {
void SetStackOverflow() { stack_overflow_ = true; }
void ClearStackOverflow() { stack_overflow_ = false; }
- // Nodes not appearing in the AST, including slots.
- virtual void VisitSlot(Slot* node) { UNREACHABLE(); }
-
// Individual AST nodes.
#define DEF_VISIT(type) \
virtual void Visit##type(type* node) = 0;
diff --git a/src/bignum-dtoa.cc b/src/bignum-dtoa.cc
index 088dd79f..a9616909 100644
--- a/src/bignum-dtoa.cc
+++ b/src/bignum-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -27,7 +27,10 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
+
#include "bignum-dtoa.h"
#include "bignum.h"
diff --git a/src/bignum.h b/src/bignum.h
index 1d2bff61..dcc4fa70 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -92,6 +92,7 @@ class Bignum {
static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) < 0;
}
+
private:
typedef uint32_t Chunk;
typedef uint64_t DoubleChunk;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 9f01664d..f07e625e 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -350,7 +350,14 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
prototype,
call_code,
is_ecma_native);
- SetLocalPropertyNoThrow(target, symbol, function, DONT_ENUM);
+ PropertyAttributes attributes;
+ if (target->IsJSBuiltinsObject()) {
+ attributes =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ } else {
+ attributes = DONT_ENUM;
+ }
+ SetLocalPropertyNoThrow(target, symbol, function, attributes);
if (is_ecma_native) {
function->shared()->set_instance_class_name(*symbol);
}
@@ -1060,7 +1067,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
- new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
// Set up a well-formed parameter map to make assertions happy.
Handle<FixedArray> elements = factory->NewFixedArray(2);
elements->set_map(heap->non_strict_arguments_elements_map());
@@ -1677,7 +1684,6 @@ bool Genesis::InstallNatives() {
global_context()->set_regexp_result_map(*initial_map);
}
-
#ifdef DEBUG
builtins->Verify();
#endif
@@ -2056,7 +2062,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
break;
}
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
// Ignore non-properties.
diff --git a/src/builtins.cc b/src/builtins.cc
index d403a951..e6a0699f 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1583,7 +1583,6 @@ void Builtins::InitBuiltinFunctionTable() {
functions->s_name = #aname; \
functions->name = k##aname; \
functions->flags = Code::ComputeFlags(Code::kind, \
- NOT_IN_LOOP, \
state, \
extra); \
functions->extra_args = NO_EXTRA_ARGUMENTS; \
diff --git a/src/builtins.h b/src/builtins.h
index f9a5a13b..31090d3a 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -238,6 +238,8 @@ enum BuiltinExtraArguments {
V(FILTER_KEY, 1) \
V(CALL_NON_FUNCTION, 0) \
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
+ V(CALL_FUNCTION_PROXY, 1) \
+ V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \
V(TO_OBJECT, 0) \
V(TO_NUMBER, 0) \
V(TO_STRING, 0) \
diff --git a/src/cached-powers.h b/src/cached-powers.h
index 2ae56196..88df2226 100644
--- a/src/cached-powers.h
+++ b/src/cached-powers.h
@@ -35,7 +35,6 @@ namespace internal {
class PowersOfTenCache {
public:
-
// Not all powers of ten are cached. The decimal exponent of two neighboring
// cached numbers will differ by kDecimalExponentDistance.
static const int kDecimalExponentDistance;
diff --git a/src/circular-queue-inl.h b/src/circular-queue-inl.h
index 349f2229..373bf609 100644
--- a/src/circular-queue-inl.h
+++ b/src/circular-queue-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -25,8 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef V8_CIRCULAR_BUFFER_INL_H_
-#define V8_CIRCULAR_BUFFER_INL_H_
+#ifndef V8_CIRCULAR_QUEUE_INL_H_
+#define V8_CIRCULAR_QUEUE_INL_H_
#include "circular-queue.h"
@@ -50,4 +50,4 @@ void SamplingCircularQueue::WrapPositionIfNeeded(
} } // namespace v8::internal
-#endif // V8_CIRCULAR_BUFFER_INL_H_
+#endif // V8_CIRCULAR_QUEUE_INL_H_
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 5535d171..00da4cba 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -61,7 +61,7 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
}
-SmartPointer<const char> CodeStub::GetName() {
+SmartArrayPointer<const char> CodeStub::GetName() {
char buffer[100];
NoAllocationStringAllocator allocator(buffer,
static_cast<unsigned>(sizeof(buffer)));
@@ -75,7 +75,7 @@ void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
code->set_major_key(MajorKey());
Isolate* isolate = masm->isolate();
- SmartPointer<const char> name = GetName();
+ SmartArrayPointer<const char> name = GetName();
PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
Counters* counters = isolate->counters();
@@ -114,7 +114,6 @@ Handle<Code> CodeStub::GetCode() {
// Copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
static_cast<Code::Kind>(GetCodeKind()),
- InLoop(),
GetICState());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
@@ -152,7 +151,6 @@ MaybeObject* CodeStub::TryGetCode() {
// Try to copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
static_cast<Code::Kind>(GetCodeKind()),
- InLoop(),
GetICState());
Object* new_object;
{ MaybeObject* maybe_new_object =
@@ -246,27 +244,27 @@ void InstanceofStub::PrintName(StringStream* stream) {
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
- case JSObject::FAST_ELEMENTS:
+ case FAST_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break;
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
break;
- case JSObject::DICTIONARY_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
break;
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -275,28 +273,28 @@ void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
- case JSObject::FAST_ELEMENTS:
+ case FAST_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
break;
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_js_array_);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
break;
- case JSObject::DICTIONARY_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
break;
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -316,17 +314,12 @@ void ArgumentsAccessStub::PrintName(StringStream* stream) {
void CallFunctionStub::PrintName(StringStream* stream) {
- const char* in_loop_name = NULL; // Make g++ happy.
- switch (in_loop_) {
- case NOT_IN_LOOP: in_loop_name = ""; break;
- case IN_LOOP: in_loop_name = "_InLoop"; break;
- }
const char* flags_name = NULL; // Make g++ happy.
switch (flags_) {
case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
}
- stream->Add("CallFunctionStub_Args%d%s%s", argc_, in_loop_name, flags_name);
+ stream->Add("CallFunctionStub_Args%d%s", argc_, flags_name);
}
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 89e99a8d..64c89b93 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -168,10 +168,6 @@ class CodeStub BASE_EMBEDDED {
virtual Major MajorKey() = 0;
virtual int MinorKey() = 0;
- // The CallFunctionStub needs to override this so it can encode whether a
- // lazily generated function should be fully optimized or not.
- virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
-
// BinaryOpStub needs to override this.
virtual int GetCodeKind();
@@ -181,7 +177,7 @@ class CodeStub BASE_EMBEDDED {
}
// Returns a name for logging/debugging purposes.
- SmartPointer<const char> GetName();
+ SmartArrayPointer<const char> GetName();
virtual void PrintName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
@@ -646,8 +642,8 @@ class RegExpConstructResultStub: public CodeStub {
class CallFunctionStub: public CodeStub {
public:
- CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
- : argc_(argc), in_loop_(in_loop), flags_(flags) { }
+ CallFunctionStub(int argc, CallFunctionFlags flags)
+ : argc_(argc), flags_(flags) { }
void Generate(MacroAssembler* masm);
@@ -657,26 +653,20 @@ class CallFunctionStub: public CodeStub {
private:
int argc_;
- InLoopFlag in_loop_;
CallFunctionFlags flags_;
virtual void PrintName(StringStream* stream);
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
- class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
- class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
- class ArgcBits: public BitField<int, 2, 32 - 2> {};
+ class FlagBits: public BitField<CallFunctionFlags, 0, 1> {};
+ class ArgcBits: public BitField<unsigned, 1, 32 - 1> {};
Major MajorKey() { return CallFunction; }
int MinorKey() {
// Encode the parameters in a unique 32 bit value.
- return InLoopBits::encode(in_loop_)
- | FlagBits::encode(flags_)
- | ArgcBits::encode(argc_);
+ return FlagBits::encode(flags_) | ArgcBits::encode(argc_);
}
- InLoopFlag InLoop() { return in_loop_; }
-
bool ReceiverMightBeImplicit() {
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
}
@@ -860,7 +850,7 @@ class AllowStubCallsScope {
class KeyedLoadElementStub : public CodeStub {
public:
- explicit KeyedLoadElementStub(JSObject::ElementsKind elements_kind)
+ explicit KeyedLoadElementStub(ElementsKind elements_kind)
: elements_kind_(elements_kind)
{ }
@@ -870,7 +860,7 @@ class KeyedLoadElementStub : public CodeStub {
void Generate(MacroAssembler* masm);
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
DISALLOW_COPY_AND_ASSIGN(KeyedLoadElementStub);
};
@@ -879,20 +869,20 @@ class KeyedLoadElementStub : public CodeStub {
class KeyedStoreElementStub : public CodeStub {
public:
KeyedStoreElementStub(bool is_js_array,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: is_js_array_(is_js_array),
elements_kind_(elements_kind) { }
Major MajorKey() { return KeyedStoreElement; }
int MinorKey() {
- return (is_js_array_ ? 0 : JSObject::kElementsKindCount) + elements_kind_;
+ return (is_js_array_ ? 0 : kElementsKindCount) + elements_kind_;
}
void Generate(MacroAssembler* masm);
private:
bool is_js_array_;
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub);
};
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index 1fcf7531..4339d226 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -242,6 +242,7 @@ class CompilationCache {
// cache during debugging to make sure new scripts are always compiled.
void Enable();
void Disable();
+
private:
explicit CompilationCache(Isolate* isolate);
~CompilationCache();
diff --git a/src/compiler.cc b/src/compiler.cc
index b33c374d..5e1c4a97 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -41,6 +41,7 @@
#include "parser.h"
#include "rewriter.h"
#include "runtime-profiler.h"
+#include "scanner-character-streams.h"
#include "scopeinfo.h"
#include "scopes.h"
#include "vm-state-inl.h"
diff --git a/src/compiler.h b/src/compiler.h
index 181446b2..69ab27d9 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -49,11 +49,11 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(Isolate::Current() == isolate_);
return isolate_;
}
- bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
- bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
- bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
- bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; }
- bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
+ bool is_lazy() const { return IsLazy::decode(flags_); }
+ bool is_eval() const { return IsEval::decode(flags_); }
+ bool is_global() const { return IsGlobal::decode(flags_); }
+ bool is_strict_mode() const { return IsStrictMode::decode(flags_); }
+ bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
Handle<Code> code() const { return code_; }
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index 1a20645a..41cf0d54 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -32,19 +32,22 @@
#include <math.h>
#include <float.h> // Required for DBL_MAX and on Win32 for finite()
#include <stdarg.h>
+#include "globals.h" // Required for V8_INFINITY
// ----------------------------------------------------------------------------
// Extra POSIX/ANSI functions for Win32/MSVC.
#include "conversions.h"
-#include "strtod.h"
+#include "double.h"
#include "platform.h"
+#include "scanner.h"
+#include "strtod.h"
namespace v8 {
namespace internal {
static inline double JunkStringValue() {
- return BitCast<double, uint64_t>(kQuietNaNMask);
+ return std::numeric_limits<double>::quiet_NaN();
}
@@ -87,12 +90,15 @@ static inline double DoubleToInteger(double x) {
int32_t DoubleToInt32(double x) {
int32_t i = FastD2I(x);
if (FastI2D(i) == x) return i;
- static const double two32 = 4294967296.0;
- static const double two31 = 2147483648.0;
- if (!isfinite(x) || x == 0) return 0;
- if (x < 0 || x >= two32) x = modulo(x, two32);
- x = (x >= 0) ? floor(x) : ceil(x) + two32;
- return (int32_t) ((x >= two31) ? x - two32 : x);
+ Double d(x);
+ int exponent = d.Exponent();
+ if (exponent < 0) {
+ if (exponent <= -Double::kSignificandSize) return 0;
+ return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent);
+ } else {
+ if (exponent > 31) return 0;
+ return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
+ }
}
diff --git a/src/conversions.cc b/src/conversions.cc
index c34fe519..5bfddd04 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -26,11 +26,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
+#include <math.h>
#include <limits.h>
#include "conversions-inl.h"
#include "dtoa.h"
-#include "scanner-base.h"
#include "strtod.h"
#include "utils.h"
@@ -38,7 +38,6 @@ namespace v8 {
namespace internal {
-
double StringToDouble(UnicodeCache* unicode_cache,
const char* str, int flags, double empty_string_val) {
const char* end = str + StrLength(str);
@@ -390,7 +389,7 @@ char* DoubleToRadixCString(double value, int radix) {
int integer_pos = kBufferSize - 2;
do {
integer_buffer[integer_pos--] =
- chars[static_cast<int>(modulo(integer_part, radix))];
+ chars[static_cast<int>(fmod(integer_part, radix))];
integer_part /= radix;
} while (integer_part >= 1.0);
// Sanity check.
diff --git a/src/conversions.h b/src/conversions.h
index 9c0b8f35..e51ad650 100644
--- a/src/conversions.h
+++ b/src/conversions.h
@@ -28,12 +28,15 @@
#ifndef V8_CONVERSIONS_H_
#define V8_CONVERSIONS_H_
-#include "scanner-base.h"
+#include <limits>
+
#include "utils.h"
namespace v8 {
namespace internal {
+class UnicodeCache;
+
// Maximum number of significant digits in decimal representation.
// The longest possible double in decimal representation is
// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
@@ -44,14 +47,14 @@ namespace internal {
const int kMaxSignificantDigits = 772;
-static bool isDigit(int x, int radix) {
+static inline bool isDigit(int x, int radix) {
return (x >= '0' && x <= '9' && x < '0' + radix)
|| (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
|| (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
}
-static double SignedZero(bool negative) {
+static inline double SignedZero(bool negative) {
return negative ? -0.0 : 0.0;
}
@@ -124,6 +127,8 @@ double StringToDouble(UnicodeCache* unicode_cache,
int flags,
double empty_string_val = 0);
+const int kDoubleToCStringMinBufferSize = 100;
+
// Converts a double to a string value according to ECMA-262 9.8.1.
// The buffer should be large enough for any floating point number.
// 100 characters is enough.
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index 938b6322..4982197c 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -51,11 +51,6 @@ void CodeMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
}
-void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->DeleteCode(start);
-}
-
-
void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->MoveCode(from, to);
}
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 8b3333ea..d74c034a 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -137,16 +137,6 @@ void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
}
-void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
- CodeEventsContainer evt_rec;
- CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
- rec->type = CodeEventRecord::CODE_DELETE;
- rec->order = ++enqueue_order_;
- rec->start = from;
- events_buffer_.Enqueue(evt_rec);
-}
-
-
void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
Address to) {
CodeEventsContainer evt_rec;
@@ -425,7 +415,6 @@ void CpuProfiler::CodeMoveEvent(Address from, Address to) {
void CpuProfiler::CodeDeleteEvent(Address from) {
- Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 4175e8f6..a71c0e0a 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -48,7 +48,6 @@ class TokenEnumerator;
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \
- V(CODE_DELETE, CodeDeleteEventRecord) \
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
@@ -87,14 +86,6 @@ class CodeMoveEventRecord : public CodeEventRecord {
};
-class CodeDeleteEventRecord : public CodeEventRecord {
- public:
- Address start;
-
- INLINE(void UpdateCodeMap(CodeMap* code_map));
-};
-
-
class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
public:
Address from;
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 06622057..adefba73 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -221,14 +221,14 @@ void RemoteDebugger::Run() {
}
-void RemoteDebugger::MessageReceived(i::SmartPointer<char> message) {
+void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
AddEvent(event);
}
-void RemoteDebugger::KeyboardCommand(i::SmartPointer<char> command) {
+void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
AddEvent(event);
@@ -238,7 +238,7 @@ void RemoteDebugger::KeyboardCommand(i::SmartPointer<char> command) {
void RemoteDebugger::ConnectionClosed() {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
- i::SmartPointer<char>());
+ i::SmartArrayPointer<char>());
AddEvent(event);
}
@@ -330,14 +330,14 @@ void RemoteDebugger::HandleKeyboardCommand(char* command) {
void ReceiverThread::Run() {
// Receive the connect message (with empty body).
- i::SmartPointer<char> message =
- i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+ i::SmartArrayPointer<char> message =
+ i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
ASSERT(*message == NULL);
while (true) {
// Receive a message.
- i::SmartPointer<char> message =
- i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+ i::SmartArrayPointer<char> message =
+ i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
if (*message == NULL) {
remote_debugger_->ConnectionClosed();
return;
@@ -361,7 +361,7 @@ void KeyboardThread::Run() {
// Pass the keyboard command to the main thread.
remote_debugger_->KeyboardCommand(
- i::SmartPointer<char>(i::StrDup(command)));
+ i::SmartArrayPointer<char>(i::StrDup(command)));
}
}
diff --git a/src/d8-debug.h b/src/d8-debug.h
index 4e33e6f4..aeff3c12 100644
--- a/src/d8-debug.h
+++ b/src/d8-debug.h
@@ -61,8 +61,8 @@ class RemoteDebugger {
void Run();
// Handle events from the subordinate threads.
- void MessageReceived(i::SmartPointer<char> message);
- void KeyboardCommand(i::SmartPointer<char> command);
+ void MessageReceived(i::SmartArrayPointer<char> message);
+ void KeyboardCommand(i::SmartArrayPointer<char> command);
void ConnectionClosed();
private:
@@ -127,7 +127,7 @@ class KeyboardThread: public i::Thread {
// Events processed by the main deubgger thread.
class RemoteDebuggerEvent {
public:
- RemoteDebuggerEvent(int type, i::SmartPointer<char> data)
+ RemoteDebuggerEvent(int type, i::SmartArrayPointer<char> data)
: type_(type), data_(data), next_(NULL) {
ASSERT(type == kMessage || type == kKeyboard || type == kDisconnect);
}
@@ -144,7 +144,7 @@ class RemoteDebuggerEvent {
RemoteDebuggerEvent* next() { return next_; }
int type_;
- i::SmartPointer<char> data_;
+ i::SmartArrayPointer<char> data_;
RemoteDebuggerEvent* next_;
friend class RemoteDebugger;
diff --git a/src/d8-posix.cc b/src/d8-posix.cc
index 658fd4ff..289c3b0a 100644
--- a/src/d8-posix.cc
+++ b/src/d8-posix.cc
@@ -231,6 +231,7 @@ class ExecArgs {
static const unsigned kMaxArgs = 1000;
char** arg_array() { return exec_args_; }
char* arg0() { return exec_args_[0]; }
+
private:
char* exec_args_[kMaxArgs + 1];
};
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index 08395e53..71be9331 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -49,7 +49,7 @@ namespace v8 {
class ReadLineEditor: public LineEditor {
public:
ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
- virtual i::SmartPointer<char> Prompt(const char* prompt);
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt);
virtual bool Open();
virtual bool Close();
virtual void AddHistory(const char* str);
@@ -72,6 +72,7 @@ bool ReadLineEditor::Open() {
rl_completer_word_break_characters = kWordBreakCharacters;
rl_bind_key('\t', rl_complete);
using_history();
+ stifle_history(Shell::kMaxHistoryEntries);
return read_history(Shell::kHistoryFileName) == 0;
}
@@ -81,13 +82,25 @@ bool ReadLineEditor::Close() {
}
-i::SmartPointer<char> ReadLineEditor::Prompt(const char* prompt) {
+i::SmartArrayPointer<char> ReadLineEditor::Prompt(const char* prompt) {
char* result = readline(prompt);
- return i::SmartPointer<char>(result);
+ return i::SmartArrayPointer<char>(result);
}
void ReadLineEditor::AddHistory(const char* str) {
+ // Do not record empty input.
+ if (strlen(str) == 0) return;
+ // Remove duplicate history entry.
+ history_set_pos(history_length-1);
+ if (current_history()) {
+ do {
+ if (strcmp(current_history()->line, str) == 0) {
+ remove_history(where_history());
+ break;
+ }
+ } while (previous_history());
+ }
add_history(str);
}
@@ -105,7 +118,7 @@ char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
static unsigned current_index;
static Persistent<Array> current_completions;
if (state == 0) {
- i::SmartPointer<char> full_text(i::StrNDup(rl_line_buffer, rl_point));
+ i::SmartArrayPointer<char> full_text(i::StrNDup(rl_line_buffer, rl_point));
HandleScope scope;
Handle<Array> completions =
Shell::GetCompletions(String::New(text), String::New(*full_text));
diff --git a/src/d8.cc b/src/d8.cc
index 4d7e988a..55f0d4c2 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -70,6 +70,7 @@ namespace v8 {
#ifndef V8_SHARED
LineEditor *LineEditor::first_ = NULL;
const char* Shell::kHistoryFileName = ".d8_history";
+const int Shell::kMaxHistoryEntries = 1000;
LineEditor::LineEditor(Type type, const char* name)
@@ -95,19 +96,19 @@ LineEditor* LineEditor::Get() {
class DumbLineEditor: public LineEditor {
public:
DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
- virtual i::SmartPointer<char> Prompt(const char* prompt);
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt);
};
static DumbLineEditor dumb_line_editor;
-i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
+i::SmartArrayPointer<char> DumbLineEditor::Prompt(const char* prompt) {
static const int kBufferSize = 256;
char buffer[kBufferSize];
printf("%s", prompt);
char* str = fgets(buffer, kBufferSize, stdin);
- return i::SmartPointer<char>(str ? i::StrDup(str) : str);
+ return i::SmartArrayPointer<char>(str ? i::StrDup(str) : str);
}
@@ -117,6 +118,7 @@ CounterCollection Shell::local_counters_;
CounterCollection* Shell::counters_ = &local_counters_;
i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Persistent<Context> Shell::utility_context_;
+LineEditor* Shell::console = NULL;
#endif // V8_SHARED
Persistent<Context> Shell::evaluation_context_;
@@ -176,8 +178,8 @@ bool Shell::ExecuteString(Handle<String> source,
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
- const char* cstr = ToCString(str);
- printf("%s\n", cstr);
+ fwrite(*str, sizeof(**str), str.length(), stdout);
+ printf("\n");
}
return true;
}
@@ -203,13 +205,25 @@ Handle<Value> Shell::Write(const Arguments& args) {
int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
if (n != str.length()) {
printf("Error in fwrite\n");
- exit(1);
+ Exit(1);
}
}
return Undefined();
}
+Handle<Value> Shell::EnableProfiler(const Arguments& args) {
+ V8::ResumeProfiler();
+ return Undefined();
+}
+
+
+Handle<Value> Shell::DisableProfiler(const Arguments& args) {
+ V8::PauseProfiler();
+ return Undefined();
+}
+
+
Handle<Value> Shell::Read(const Arguments& args) {
String::Utf8Value file(args[0]);
if (*file == NULL) {
@@ -259,7 +273,7 @@ Handle<Value> Shell::Load(const Arguments& args) {
if (source.IsEmpty()) {
return ThrowException(String::New("Error loading file"));
}
- if (!ExecuteString(source, String::New(*file), false, false)) {
+ if (!ExecuteString(source, String::New(*file), false, true)) {
return ThrowException(String::New("Error executing file"));
}
}
@@ -283,18 +297,20 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
size_t length = 0;
if (args[0]->IsUint32()) {
length = args[0]->Uint32Value();
- } else if (args[0]->IsNumber()) {
- double raw_length = args[0]->NumberValue();
+ } else {
+ Local<Number> number = args[0]->ToNumber();
+ if (number.IsEmpty() || !number->IsNumber()) {
+ return ThrowException(String::New("Array length must be a number."));
+ }
+ int32_t raw_length = number->ToInt32()->Int32Value();
if (raw_length < 0) {
return ThrowException(String::New("Array length must not be negative."));
}
- if (raw_length > kMaxLength) {
+ if (raw_length > static_cast<int32_t>(kMaxLength)) {
return ThrowException(
String::New("Array length exceeds maximum length."));
}
length = static_cast<size_t>(raw_length);
- } else {
- return ThrowException(String::New("Array length must be a number."));
}
if (length > static_cast<size_t>(kMaxLength)) {
return ThrowException(String::New("Array length exceeds maximum length."));
@@ -427,6 +443,7 @@ void Shell::ReportException(v8::TryCatch* try_catch) {
printf("%s\n", stack_trace_string);
}
}
+ printf("\n");
}
@@ -506,7 +523,7 @@ void Shell::MapCounters(const char* name) {
NULL : counters_file_->memory();
if (memory == NULL) {
printf("Could not map counters file %s\n", name);
- exit(1);
+ Exit(1);
}
counters_ = static_cast<CounterCollection*>(memory);
V8::SetCounterFunction(LookupCounter);
@@ -656,6 +673,10 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
global_template->Set(String::New("version"), FunctionTemplate::New(Version));
+ global_template->Set(String::New("enableProfiler"),
+ FunctionTemplate::New(EnableProfiler));
+ global_template->Set(String::New("disableProfiler"),
+ FunctionTemplate::New(DisableProfiler));
// Bind the handlers for external arrays.
global_template->Set(String::New("Int8Array"),
@@ -683,7 +704,7 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
global_template->Set(String::New("lol_is_enabled"), False());
#endif
-#ifndef V8_SHARED
+#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
AddOSMethods(os_templ);
global_template->Set(String::New("os"), os_templ);
@@ -699,7 +720,7 @@ void Shell::Initialize() {
int bz2_result = startup_data_decompressor.Decompress();
if (bz2_result != BZ_OK) {
fprintf(stderr, "bzip error code: %d\n", bz2_result);
- exit(1);
+ Exit(1);
}
#endif
@@ -761,8 +782,18 @@ Persistent<Context> Shell::CreateEvaluationContext() {
}
+void Shell::Exit(int exit_code) {
+ // Use _exit instead of exit to avoid races between isolate
+ // threads and static destructors.
+ fflush(stdout);
+ fflush(stderr);
+ _exit(exit_code);
+}
+
+
#ifndef V8_SHARED
void Shell::OnExit() {
+ if (console != NULL) console->Close();
if (i::FLAG_dump_counters) {
printf("+----------------------------------------+-------------+\n");
printf("| Name | Value |\n");
@@ -864,22 +895,22 @@ Handle<String> Shell::ReadFile(const char* name) {
void Shell::RunShell() {
Locker locker;
Context::Scope context_scope(evaluation_context_);
- HandleScope handle_scope;
+ HandleScope outer_scope;
Handle<String> name = String::New("(d8)");
#ifndef V8_SHARED
- LineEditor* editor = LineEditor::Get();
- printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
+ console = LineEditor::Get();
+ printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
if (i::FLAG_debugger) {
printf("JavaScript debugger enabled\n");
}
- editor->Open();
+ console->Open();
while (true) {
- i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
+ i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
if (input.is_empty()) break;
- editor->AddHistory(*input);
+ console->AddHistory(*input);
+ HandleScope inner_scope;
ExecuteString(String::New(*input), name, true, true);
}
- editor->Close();
#else
printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
static const int kBufferSize = 256;
@@ -887,6 +918,7 @@ void Shell::RunShell() {
char buffer[kBufferSize];
printf("%s", Shell::kPrompt);
if (fgets(buffer, kBufferSize, stdin) == NULL) break;
+ HandleScope inner_scope;
ExecuteString(String::New(buffer), name, true, true);
}
#endif // V8_SHARED
@@ -897,18 +929,24 @@ void Shell::RunShell() {
#ifndef V8_SHARED
class ShellThread : public i::Thread {
public:
- ShellThread(int no, i::Vector<const char> files)
+ // Takes ownership of the underlying char array of |files|.
+ ShellThread(int no, char* files)
: Thread("d8:ShellThread"),
no_(no), files_(files) { }
+
+ ~ShellThread() {
+ delete[] files_;
+ }
+
virtual void Run();
private:
int no_;
- i::Vector<const char> files_;
+ char* files_;
};
void ShellThread::Run() {
- char* ptr = const_cast<char*>(files_.start());
+ char* ptr = files_;
while ((ptr != NULL) && (*ptr != '\0')) {
// For each newline-separated line.
char* next_line = ReadLine(ptr);
@@ -921,23 +959,24 @@ void ShellThread::Run() {
// Prepare the context for this thread.
Locker locker;
- HandleScope scope;
+ HandleScope outer_scope;
Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Context::Scope context_scope(thread_context);
while ((ptr != NULL) && (*ptr != '\0')) {
+ HandleScope inner_scope;
char* filename = ptr;
ptr = ReadWord(ptr);
// Skip empty strings.
if (strlen(filename) == 0) {
- break;
+ continue;
}
Handle<String> str = Shell::ReadFile(filename);
if (str.IsEmpty()) {
- printf("WARNING: %s not found\n", filename);
- break;
+ printf("File '%s' not found\n", filename);
+ Shell::Exit(1);
}
Shell::ExecuteString(str, String::New(filename), false, false);
@@ -950,12 +989,15 @@ void ShellThread::Run() {
#endif // V8_SHARED
-void SourceGroup::ExitShell(int exit_code) {
- // Use _exit instead of exit to avoid races between isolate
- // threads and static destructors.
- fflush(stdout);
- fflush(stderr);
- _exit(exit_code);
+SourceGroup::~SourceGroup() {
+#ifndef V8_SHARED
+ delete next_semaphore_;
+ next_semaphore_ = NULL;
+ delete done_semaphore_;
+ done_semaphore_ = NULL;
+ delete thread_;
+ thread_ = NULL;
+#endif // V8_SHARED
}
@@ -968,8 +1010,7 @@ void SourceGroup::Execute() {
Handle<String> file_name = String::New("unnamed");
Handle<String> source = String::New(argv_[i + 1]);
if (!Shell::ExecuteString(source, file_name, false, true)) {
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
++i;
} else if (arg[0] == '-') {
@@ -981,12 +1022,10 @@ void SourceGroup::Execute() {
Handle<String> source = ReadFile(arg);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", arg);
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
if (!Shell::ExecuteString(source, file_name, false, true)) {
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
}
}
@@ -1050,7 +1089,6 @@ void SourceGroup::WaitForThread() {
if (thread_ == NULL) return;
if (Shell::options.last_run) {
thread_->Join();
- thread_ = NULL;
} else {
done_semaphore_->Wait();
}
@@ -1123,14 +1161,18 @@ bool Shell::SetOptions(int argc, char* argv[]) {
return false;
#endif // V8_SHARED
options.num_isolates++;
+ } else if (strcmp(argv[i], "-p") == 0) {
+#ifdef V8_SHARED
+ printf("D8 with shared library does not support multi-threading\n");
+ return false;
+#else
+ options.num_parallel_files++;
+#endif // V8_SHARED
}
#ifdef V8_SHARED
else if (strcmp(argv[i], "--dump-counters") == 0) {
printf("D8 with shared library does not include counters\n");
return false;
- } else if (strcmp(argv[i], "-p") == 0) {
- printf("D8 with shared library does not support multi-threading\n");
- return false;
} else if (strcmp(argv[i], "--debugger") == 0) {
printf("Javascript debugger not included\n");
return false;
@@ -1140,6 +1182,8 @@ bool Shell::SetOptions(int argc, char* argv[]) {
#ifndef V8_SHARED
// Run parallel threads if we are not using --isolate
+ options.parallel_files = new char*[options.num_parallel_files];
+ int parallel_files_set = 0;
for (int i = 1; i < argc; i++) {
if (argv[i] == NULL) continue;
if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
@@ -1148,25 +1192,21 @@ bool Shell::SetOptions(int argc, char* argv[]) {
return false;
}
argv[i] = NULL;
- if (options.parallel_files == NULL) {
- options.parallel_files = new i::List<i::Vector<const char> >();
- }
- int size = 0;
- const char* files = ReadChars(argv[++i], &size);
- if (files == NULL) {
- printf("-p option incomplete\n");
- return false;
- }
+ i++;
+ options.parallel_files[parallel_files_set] = argv[i];
+ parallel_files_set++;
argv[i] = NULL;
- options.parallel_files->Add(i::Vector<const char>(files, size));
- delete[] files;
}
}
+ if (parallel_files_set != options.num_parallel_files) {
+ printf("-p requires a file containing a list of files as parameter\n");
+ return false;
+ }
#endif // V8_SHARED
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
- // set up isolated source groups
+ // Set up isolated source groups.
options.isolate_sources = new SourceGroup[options.num_isolates];
SourceGroup* current = options.isolate_sources;
current->Begin(argv, 1);
@@ -1189,14 +1229,22 @@ bool Shell::SetOptions(int argc, char* argv[]) {
int Shell::RunMain(int argc, char* argv[]) {
#ifndef V8_SHARED
i::List<i::Thread*> threads(1);
- if (options.parallel_files != NULL)
- for (int i = 0; i < options.parallel_files->length(); i++) {
- i::Vector<const char> files = options.parallel_files->at(i);
+ if (options.parallel_files != NULL) {
+ for (int i = 0; i < options.num_parallel_files; i++) {
+ char* files = NULL;
+ { Locker lock(Isolate::GetCurrent());
+ int size = 0;
+ files = ReadChars(options.parallel_files[i], &size);
+ }
+ if (files == NULL) {
+ printf("File list '%s' not found\n", options.parallel_files[i]);
+ Exit(1);
+ }
ShellThread* thread = new ShellThread(threads.length(), files);
thread->Start();
threads.Add(thread);
}
-
+ }
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
}
@@ -1205,29 +1253,20 @@ int Shell::RunMain(int argc, char* argv[]) {
Locker lock;
HandleScope scope;
Persistent<Context> context = CreateEvaluationContext();
- if (options.last_run) {
- // Keep using the same context in the interactive shell.
- evaluation_context_ = context;
-#ifndef V8_SHARED
- // 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();
- }
-#endif // V8_SHARED
- }
{
Context::Scope cscope(context);
options.isolate_sources[0].Execute();
}
- if (!options.last_run) {
+ if (options.last_run) {
+ // Keep using the same context in the interactive shell
+ evaluation_context_ = context;
+ } else {
context.Dispose();
}
#ifndef V8_SHARED
// Start preemption if threads have been created and preemption is enabled.
- if (options.parallel_files != NULL
- && threads.length() > 0
+ if (threads.length() > 0
&& options.use_preemption) {
Locker::StartPreemption(options.preemption_interval);
}
@@ -1239,12 +1278,16 @@ int Shell::RunMain(int argc, char* argv[]) {
options.isolate_sources[i].WaitForThread();
}
- if (options.parallel_files != NULL)
- for (int i = 0; i < threads.length(); i++) {
- i::Thread* thread = threads[i];
- thread->Join();
- delete thread;
- }
+ for (int i = 0; i < threads.length(); i++) {
+ i::Thread* thread = threads[i];
+ thread->Join();
+ delete thread;
+ }
+
+ if (threads.length() > 0 && options.use_preemption) {
+ Locker lock;
+ Locker::StopPreemption();
+ }
#endif // V8_SHARED
return 0;
}
@@ -1289,9 +1332,7 @@ int Shell::Main(int argc, char* argv[]) {
|| !options.script_executed )
&& !options.test_shell ) {
#ifndef V8_SHARED
- if (!i::FLAG_debugger) {
- InstallUtilityScript();
- }
+ InstallUtilityScript();
#endif // V8_SHARED
RunShell();
}
diff --git a/src/d8.h b/src/d8.h
index 28321f56..15d8d5d5 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -28,11 +28,11 @@
#ifndef V8_D8_H_
#define V8_D8_H_
-
#ifndef V8_SHARED
-#include "v8.h"
#include "allocation.h"
#include "hashmap.h"
+#include "smart-array-pointer.h"
+#include "v8.h"
#else
#include "../include/v8.h"
#endif // V8_SHARED
@@ -116,6 +116,29 @@ class CounterMap {
#endif // V8_SHARED
+#ifndef V8_SHARED
+class LineEditor {
+ public:
+ enum Type { DUMB = 0, READLINE = 1 };
+ LineEditor(Type type, const char* name);
+ virtual ~LineEditor() { }
+
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt) = 0;
+ virtual bool Open() { return true; }
+ virtual bool Close() { return true; }
+ virtual void AddHistory(const char* str) { }
+
+ const char* name() { return name_; }
+ static LineEditor* Get();
+ private:
+ Type type_;
+ const char* name_;
+ LineEditor* next_;
+ static LineEditor* first_;
+};
+#endif // V8_SHARED
+
+
class SourceGroup {
public:
SourceGroup() :
@@ -126,7 +149,9 @@ class SourceGroup {
#endif // V8_SHARED
argv_(NULL),
begin_offset_(0),
- end_offset_(0) { }
+ end_offset_(0) {}
+
+ ~SourceGroup();
void Begin(char** argv, int offset) {
argv_ = const_cast<const char**>(argv);
@@ -178,6 +203,7 @@ class ShellOptions {
#ifndef V8_SHARED
use_preemption(true),
preemption_interval(10),
+ num_parallel_files(0),
parallel_files(NULL),
#endif // V8_SHARED
script_executed(false),
@@ -189,10 +215,18 @@ class ShellOptions {
num_isolates(1),
isolate_sources(NULL) { }
+ ~ShellOptions() {
+#ifndef V8_SHARED
+ delete[] parallel_files;
+#endif // V8_SHARED
+ delete[] isolate_sources;
+ }
+
#ifndef V8_SHARED
bool use_preemption;
int preemption_interval;
- i::List< i::Vector<const char> >* parallel_files;
+ int num_parallel_files;
+ char** parallel_files;
#endif // V8_SHARED
bool script_executed;
bool last_run;
@@ -209,6 +243,7 @@ class Shell {
#else
class Shell : public i::AllStatic {
#endif // V8_SHARED
+
public:
static bool ExecuteString(Handle<String> source,
Handle<Value> name,
@@ -220,6 +255,7 @@ class Shell : public i::AllStatic {
static Persistent<Context> CreateEvaluationContext();
static int RunMain(int argc, char* argv[]);
static int Main(int argc, char* argv[]);
+ static void Exit(int exit_code);
#ifndef V8_SHARED
static Handle<Array> GetCompletions(Handle<String> text,
@@ -248,6 +284,8 @@ class Shell : public i::AllStatic {
static Handle<Value> Yield(const Arguments& args);
static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args);
+ static Handle<Value> EnableProfiler(const Arguments& args);
+ static Handle<Value> DisableProfiler(const Arguments& args);
static Handle<Value> Read(const Arguments& args);
static Handle<Value> ReadLine(const Arguments& args);
static Handle<Value> Load(const Arguments& args);
@@ -298,6 +336,8 @@ class Shell : public i::AllStatic {
static void AddOSMethods(Handle<ObjectTemplate> os_template);
#ifndef V8_SHARED
static const char* kHistoryFileName;
+ static const int kMaxHistoryEntries;
+ static LineEditor* console;
#endif // V8_SHARED
static const char* kPrompt;
static ShellOptions options;
@@ -328,29 +368,6 @@ class Shell : public i::AllStatic {
};
-#ifndef V8_SHARED
-class LineEditor {
- public:
- enum Type { DUMB = 0, READLINE = 1 };
- LineEditor(Type type, const char* name);
- virtual ~LineEditor() { }
-
- virtual i::SmartPointer<char> Prompt(const char* prompt) = 0;
- virtual bool Open() { return true; }
- virtual bool Close() { return true; }
- virtual void AddHistory(const char* str) { }
-
- const char* name() { return name_; }
- static LineEditor* Get();
- private:
- Type type_;
- const char* name_;
- LineEditor* next_;
- static LineEditor* first_;
-};
-#endif // V8_SHARED
-
-
} // namespace v8
diff --git a/src/d8.js b/src/d8.js
index a2b9585c..3009037e 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -1786,7 +1786,7 @@ function decodeLolInfoResponse(body) {
function decodeLolListResponse(body, title) {
-
+
var result;
var total_count = body.count;
var total_size = body.size;
diff --git a/src/date.js b/src/date.js
index 79b846d4..ccefce57 100644
--- a/src/date.js
+++ b/src/date.js
@@ -1048,18 +1048,19 @@ function ResetDateCache() {
// -------------------------------------------------------------------
-function SetupDate() {
- // Setup non-enumerable properties of the Date object itself.
+function SetUpDate() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC,
"parse", DateParse,
"now", DateNow
));
- // Setup non-enumerable constructor property of the Date prototype object.
+ // Set up non-enumerable constructor property of the Date prototype object.
%SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
- // Setup non-enumerable functions of the Date prototype object and
+ // Set up non-enumerable functions of the Date prototype object and
// set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString,
@@ -1111,4 +1112,4 @@ function SetupDate() {
));
}
-SetupDate();
+SetUpDate();
diff --git a/src/dateparser.h b/src/dateparser.h
index 4bd320e9..27584ce3 100644
--- a/src/dateparser.h
+++ b/src/dateparser.h
@@ -30,14 +30,12 @@
#include "allocation.h"
#include "char-predicates-inl.h"
-#include "scanner-base.h"
namespace v8 {
namespace internal {
class DateParser : public AllStatic {
public:
-
// Parse the string as a date. If parsing succeeds, return true after
// filling out the output array as follows (all integers are Smis):
// [0]: year
@@ -235,6 +233,7 @@ class DateParser : public AllStatic {
static DateToken Invalid() {
return DateToken(kInvalidTokenTag, 0, -1);
}
+
private:
enum TagType {
kInvalidTokenTag = -6,
@@ -276,6 +275,7 @@ class DateParser : public AllStatic {
}
return false;
}
+
private:
DateToken Scan();
@@ -352,6 +352,7 @@ class DateParser : public AllStatic {
static bool IsMinute(int x) { return Between(x, 0, 59); }
static bool IsHour(int x) { return Between(x, 0, 23); }
static bool IsSecond(int x) { return Between(x, 0, 59); }
+
private:
static bool IsHour12(int x) { return Between(x, 0, 12); }
static bool IsMillisecond(int x) { return Between(x, 0, 999); }
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 520bc629..591d0b3e 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -169,7 +169,8 @@ void DebuggerAgentSession::Run() {
while (true) {
// Read data from the debugger front end.
- SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
+ SmartArrayPointer<char> message =
+ DebuggerAgentUtil::ReceiveMessage(client_);
const char* msg = *message;
bool is_closing_session = (msg == NULL);
@@ -232,7 +233,7 @@ const int DebuggerAgentUtil::kContentLengthSize =
StrLength(kContentLength);
-SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
+SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
int received;
// Read header.
@@ -250,7 +251,7 @@ SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
received = conn->Receive(&c, 1);
if (received <= 0) {
PrintF("Error %d\n", Socket::LastError());
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
// Add character to header buffer.
@@ -287,12 +288,12 @@ SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
if (strcmp(key, kContentLength) == 0) {
// Get the content length value if present and within a sensible range.
if (value == NULL || strlen(value) > 7) {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
for (int i = 0; value[i] != '\0'; i++) {
// Bail out if illegal data.
if (value[i] < '0' || value[i] > '9') {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
content_length = 10 * content_length + (value[i] - '0');
}
@@ -304,7 +305,7 @@ SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
// Return now if no body.
if (content_length == 0) {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
// Read body.
@@ -312,11 +313,11 @@ SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
received = ReceiveAll(conn, buffer, content_length);
if (received < content_length) {
PrintF("Error %d\n", Socket::LastError());
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
buffer[content_length] = '\0';
- return SmartPointer<char>(buffer);
+ return SmartArrayPointer<char>(buffer);
}
diff --git a/src/debug-agent.h b/src/debug-agent.h
index e1678719..a07fb0f4 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -72,7 +72,7 @@ class DebuggerAgent: public Thread {
void OnSessionClosed(DebuggerAgentSession* session);
Isolate* isolate_;
- SmartPointer<const char> name_; // Name of the embedding application.
+ SmartArrayPointer<const char> name_; // Name of the embedding application.
int port_; // Port to use for the agent.
Socket* server_; // Server socket for listen/accept.
bool terminate_; // Termination flag.
@@ -117,7 +117,7 @@ class DebuggerAgentUtil {
static const char* const kContentLength;
static const int kContentLengthSize;
- static SmartPointer<char> ReceiveMessage(const Socket* conn);
+ static SmartArrayPointer<char> ReceiveMessage(const Socket* conn);
static bool SendConnectMessage(const Socket* conn,
const char* embedding_host);
static bool SendMessage(const Socket* conn, const Vector<uint16_t> message);
diff --git a/src/debug.cc b/src/debug.cc
index 2d58ce1f..20cd8027 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -40,6 +40,7 @@
#include "global-handles.h"
#include "ic.h"
#include "ic-inl.h"
+#include "list.h"
#include "messages.h"
#include "natives.h"
#include "stub-cache.h"
@@ -542,6 +543,7 @@ void Debug::ThreadInit() {
thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
thread_local_.step_count_ = 0;
thread_local_.last_fp_ = 0;
+ thread_local_.queued_step_count_ = 0;
thread_local_.step_into_fp_ = 0;
thread_local_.step_out_fp_ = 0;
thread_local_.after_break_target_ = 0;
@@ -957,14 +959,49 @@ Object* Debug::Break(Arguments args) {
// Clear all current stepping setup.
ClearStepping();
- // Notify the debug event listeners.
- isolate_->debugger()->OnDebugBreak(break_points_hit, false);
+ if (thread_local_.queued_step_count_ > 0) {
+ // Perform queued steps
+ int step_count = thread_local_.queued_step_count_;
+
+ // Clear queue
+ thread_local_.queued_step_count_ = 0;
+
+ PrepareStep(StepNext, step_count);
+ } else {
+ // Notify the debug event listeners.
+ isolate_->debugger()->OnDebugBreak(break_points_hit, false);
+ }
} else if (thread_local_.last_step_action_ != StepNone) {
// Hold on to last step action as it is cleared by the call to
// ClearStepping.
StepAction step_action = thread_local_.last_step_action_;
int step_count = thread_local_.step_count_;
+ // If StepNext goes deeper in code, StepOut until original frame
+ // and keep step count queued up in the meantime.
+ if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
+ // Count frames until target frame
+ int count = 0;
+ JavaScriptFrameIterator it(isolate_);
+ while (!it.done() && it.frame()->fp() != thread_local_.last_fp_) {
+ count++;
+ it.Advance();
+ }
+
+ // If we found original frame
+ if (it.frame()->fp() == thread_local_.last_fp_) {
+ if (step_count > 1) {
+ // Save old count and action to continue stepping after
+ // StepOut
+ thread_local_.queued_step_count_ = step_count - 1;
+ }
+
+ // Set up for StepOut to reach target frame
+ step_action = StepOut;
+ step_count = count;
+ }
+ }
+
// Clear all current stepping setup.
ClearStepping();
@@ -1105,6 +1142,8 @@ void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
int* source_position) {
HandleScope scope(isolate_);
+ PrepareForBreakPoints();
+
if (!EnsureDebugInfo(shared)) {
// Return if retrieving debug info failed.
return;
@@ -1178,6 +1217,7 @@ void Debug::ClearAllBreakPoints() {
void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
+ PrepareForBreakPoints();
// Make sure the function has setup the debug info.
if (!EnsureDebugInfo(shared)) {
// Return if we failed to retrieve the debug info.
@@ -1234,6 +1274,9 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) {
void Debug::PrepareStep(StepAction step_action, int step_count) {
HandleScope scope(isolate_);
+
+ PrepareForBreakPoints();
+
ASSERT(Debug::InDebugger());
// Remember this step action and count.
@@ -1448,6 +1491,13 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
// steps before reporting break back to the debugger.
bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
JavaScriptFrame* frame) {
+ // StepNext and StepOut shouldn't bring us deeper in code, so last frame
+ // shouldn't be a parent of current frame.
+ if (thread_local_.last_step_action_ == StepNext ||
+ thread_local_.last_step_action_ == StepOut) {
+ if (frame->fp() < thread_local_.last_fp_) return true;
+ }
+
// If the step last action was step next or step in make sure that a new
// statement is hit.
if (thread_local_.last_step_action_ == StepNext ||
@@ -1676,20 +1726,26 @@ void Debug::ClearStepNext() {
}
+void Debug::PrepareForBreakPoints() {
+ // If preparing for the first break point make sure to deoptimize all
+ // functions as debugging does not work with optimized code.
+ if (!has_break_points_) {
+ Deoptimizer::DeoptimizeAll();
+ }
+}
+
+
// Ensures the debug information is present for shared.
bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
// Return if we already have the debug info for shared.
- if (HasDebugInfo(shared)) return true;
+ if (HasDebugInfo(shared)) {
+ ASSERT(shared->is_compiled());
+ return true;
+ }
// Ensure shared in compiled. Return false if this failed.
if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
- // If preparing for the first break point make sure to deoptimize all
- // functions as debugging does not work with optimized code.
- if (!has_break_points_) {
- Deoptimizer::DeoptimizeAll();
- }
-
// Create the debug info object.
Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
@@ -1739,6 +1795,8 @@ void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
HandleScope scope(isolate_);
+ PrepareForBreakPoints();
+
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
@@ -1829,6 +1887,8 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
return false;
}
+ PrepareForBreakPoints();
+
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
diff --git a/src/debug.h b/src/debug.h
index c614844a..a098040c 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -247,6 +247,8 @@ class Debug {
static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
+ void PrepareForBreakPoints();
+
// Returns whether the operation succeeded.
bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
@@ -506,6 +508,9 @@ class Debug {
// Frame pointer from last step next action.
Address last_fp_;
+ // Number of queued steps left to perform before debug event.
+ int queued_step_count_;
+
// Frame pointer for frame from which step in was performed.
Address step_into_fp_;
@@ -1026,6 +1031,7 @@ class Debug_Address {
return NULL;
}
}
+
private:
Debug::AddressId id_;
};
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 94b2ff53..5feb73d7 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -613,13 +613,11 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
intptr_t input_value = input_->GetRegister(input_reg);
if (FLAG_trace_deopt) {
PrintF(
- " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
output_[frame_index]->GetTop() + output_offset,
output_offset,
input_value,
converter.NameOfCPURegister(input_reg));
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@@ -677,12 +675,10 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
- PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
+ PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
output_offset,
input_value,
input_offset);
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 79076d6a..1e67b4cb 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -223,7 +223,7 @@ static int DecodeIt(FILE* f,
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
- SmartPointer<const char> obj_name = accumulator.ToCString();
+ SmartArrayPointer<const char> obj_name = accumulator.ToCString();
out.AddFormatted(" ;; object: %s", *obj_name);
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
const char* reference_name =
@@ -247,9 +247,6 @@ static int DecodeIt(FILE* f,
PropertyType type = code->type();
out.AddFormatted(", %s", Code::PropertyType2String(type));
}
- if (code->ic_in_loop() == IN_LOOP) {
- out.AddFormatted(", in_loop");
- }
if (kind == Code::CALL_IC || kind == Code::KEYED_CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count());
}
diff --git a/src/dtoa.cc b/src/dtoa.cc
index b857a5dc..00233a88 100644
--- a/src/dtoa.cc
+++ b/src/dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -27,7 +27,10 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
+
#include "dtoa.h"
#include "bignum-dtoa.h"
diff --git a/src/elements.cc b/src/elements.cc
index 1afc5dad..e4ecfe8d 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -401,7 +401,7 @@ class DictionaryElementsAccessor
Heap* heap = isolate->heap();
FixedArray* backing_store = FixedArray::cast(obj->elements());
bool is_arguments =
- (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
if (is_arguments) {
backing_store = FixedArray::cast(backing_store->get(1));
}
@@ -565,28 +565,28 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
switch (array->map()->instance_type()) {
case FIXED_ARRAY_TYPE:
if (array->IsDictionary()) {
- return elements_accessors_[JSObject::DICTIONARY_ELEMENTS];
+ return elements_accessors_[DICTIONARY_ELEMENTS];
} else {
- return elements_accessors_[JSObject::FAST_ELEMENTS];
+ return elements_accessors_[FAST_ELEMENTS];
}
case EXTERNAL_BYTE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
case EXTERNAL_SHORT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
case EXTERNAL_INT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_INT_ELEMENTS];
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
case EXTERNAL_FLOAT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
case EXTERNAL_DOUBLE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
case EXTERNAL_PIXEL_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS];
+ return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
default:
UNREACHABLE();
return NULL;
diff --git a/src/elements.h b/src/elements.h
index 3eae303e..851c8c3d 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -54,8 +54,8 @@ class ElementsAccessor {
Object* receiver) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind.
- static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
- ASSERT(elements_kind < JSObject::kElementsKindCount);
+ static ElementsAccessor* ForKind(ElementsKind elements_kind) {
+ ASSERT(elements_kind < kElementsKindCount);
return elements_accessors_[elements_kind];
}
diff --git a/src/execution.cc b/src/execution.cc
index bdbdca81..f36d4e49 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -149,12 +149,29 @@ Handle<Object> Execution::Call(Handle<Object> callable,
Handle<Object> receiver,
int argc,
Object*** args,
- bool* pending_exception) {
+ bool* pending_exception,
+ bool convert_receiver) {
if (!callable->IsJSFunction()) {
callable = TryGetFunctionDelegate(callable, pending_exception);
if (*pending_exception) return callable;
}
Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
+
+ // In non-strict mode, convert receiver.
+ if (convert_receiver && !receiver->IsJSReceiver() &&
+ !func->shared()->native() && !func->shared()->strict_mode()) {
+ if (receiver->IsUndefined() || receiver->IsNull()) {
+ Object* global = func->context()->global()->global_receiver();
+ // Under some circumstances, 'global' can be the JSBuiltinsObject
+ // In that case, don't rewrite.
+ // (FWIW, the same holds for GetIsolate()->global()->global_receiver().)
+ if (!global->IsJSBuiltinsObject()) receiver = Handle<Object>(global);
+ } else {
+ receiver = ToObject(receiver, pending_exception);
+ }
+ if (*pending_exception) return callable;
+ }
+
return Invoke(false, func, receiver, argc, args, pending_exception);
}
@@ -210,10 +227,17 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a function.
+ // If object is a function proxy, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_function_delegate());
}
@@ -227,10 +251,17 @@ Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
ASSERT(!object->IsJSFunction());
Isolate* isolate = Isolate::Current();
+ // If object is a function proxy, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_function_delegate());
}
@@ -253,10 +284,17 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
+ // If object is a function proxies, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_constructor_delegate());
}
@@ -274,10 +312,17 @@ Handle<Object> Execution::TryGetConstructorDelegate(
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
+ // If object is a function proxies, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_constructor_delegate());
}
@@ -553,7 +598,7 @@ Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) {
Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
- if (obj->IsJSObject()) return obj;
+ if (obj->IsSpecObject()) return obj;
RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
}
diff --git a/src/execution.h b/src/execution.h
index bb5f8045..5cd7141f 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -53,11 +53,16 @@ class Execution : public AllStatic {
// *pending_exception tells whether the invoke resulted in
// a pending exception.
//
+ // When convert_receiver is set, and the receiver is not an object,
+ // and the function called is not in strict mode, receiver is converted to
+ // an object.
+ //
static Handle<Object> Call(Handle<Object> callable,
Handle<Object> receiver,
int argc,
Object*** args,
- bool* pending_exception);
+ bool* pending_exception,
+ bool convert_receiver = false);
// Construct object from function, the caller supplies an array of
// arguments. Arguments are Object* type. After function returns,
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index b3f83fe9..9fbf3298 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -133,9 +133,11 @@ v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
void ExternalizeStringExtension::Register() {
- static ExternalizeStringExtension externalize_extension;
+ static ExternalizeStringExtension* externalize_extension = NULL;
+ if (externalize_extension == NULL)
+ externalize_extension = new ExternalizeStringExtension;
static v8::DeclareExtension externalize_extension_declaration(
- &externalize_extension);
+ externalize_extension);
}
} } // namespace v8::internal
diff --git a/src/factory.cc b/src/factory.cc
index ee5c37bf..97289266 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -465,13 +465,13 @@ Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
}
-Handle<Map> Factory::GetExternalArrayElementsMap(
+Handle<Map> Factory::GetElementsTransitionMap(
Handle<Map> src,
- ExternalArrayType array_type,
+ ElementsKind elements_kind,
bool safe_to_add_transition) {
CALL_HEAP_FUNCTION(isolate(),
- src->GetExternalArrayElementsMap(array_type,
- safe_to_add_transition),
+ src->GetElementsTransitionMap(elements_kind,
+ safe_to_add_transition),
Map);
}
@@ -922,10 +922,19 @@ Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
}
-void Factory::BecomeJSObject(Handle<JSProxy> object) {
+void Factory::BecomeJSObject(Handle<JSReceiver> object) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
- isolate()->heap()->ReinitializeJSProxyAsJSObject(*object));
+ isolate()->heap()->ReinitializeJSReceiver(
+ *object, JS_OBJECT_TYPE, JSObject::kHeaderSize));
+}
+
+
+void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ isolate()->heap()->ReinitializeJSReceiver(
+ *object, JS_FUNCTION_TYPE, JSFunction::kSize));
}
diff --git a/src/factory.h b/src/factory.h
index a69b05b3..71ae750b 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -219,9 +219,9 @@ class Factory {
Handle<Map> GetSlowElementsMap(Handle<Map> map);
- Handle<Map> GetExternalArrayElementsMap(Handle<Map> map,
- ExternalArrayType array_type,
- bool safe_to_add_transition);
+ Handle<Map> GetElementsTransitionMap(Handle<Map> map,
+ ElementsKind elements_kind,
+ bool safe_to_add_transition);
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
@@ -260,8 +260,9 @@ class Factory {
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
- // Change the type of the argument into a regular JS object and reinitialize.
- void BecomeJSObject(Handle<JSProxy> object);
+ // Change the type of the argument into a JS object/function and reinitialize.
+ void BecomeJSObject(Handle<JSReceiver> object);
+ void BecomeJSFunction(Handle<JSReceiver> object);
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
diff --git a/src/fast-dtoa.cc b/src/fast-dtoa.cc
index c7f6aa17..e62bd01f 100644
--- a/src/fast-dtoa.cc
+++ b/src/fast-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -25,7 +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.
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
#include "fast-dtoa.h"
diff --git a/src/fixed-dtoa.cc b/src/fixed-dtoa.cc
index 8ad88f65..1fd974c3 100644
--- a/src/fixed-dtoa.cc
+++ b/src/fixed-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -27,7 +27,9 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
#include "double.h"
#include "fixed-dtoa.h"
diff --git a/src/flags.cc b/src/flags.cc
index c20f5ee0..ab5b57ce 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -31,7 +31,7 @@
#include "v8.h"
#include "platform.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "string-stream.h"
@@ -193,7 +193,7 @@ static const char* Type2String(Flag::FlagType type) {
}
-static SmartPointer<const char> ToString(Flag* flag) {
+static SmartArrayPointer<const char> ToString(Flag* flag) {
HeapStringAllocator string_allocator;
StringStream buffer(&string_allocator);
switch (flag->type()) {
@@ -528,7 +528,7 @@ void FlagList::PrintHelp() {
printf("Options:\n");
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
- SmartPointer<const char> value = ToString(f);
+ SmartArrayPointer<const char> value = ToString(f);
printf(" --%s (%s)\n type: %s default: %s\n",
f->name(), f->comment(), Type2String(f->type()), *value);
}
diff --git a/src/frames.h b/src/frames.h
index 4f94ebc7..fed11c4f 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -579,6 +579,7 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
virtual void Print(StringStream* accumulator,
PrintMode mode,
int index) const;
+
protected:
explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) { }
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index ca2026bb..80738741 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -96,11 +96,6 @@ void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
}
-void BreakableStatementChecker::VisitExitContextStatement(
- ExitContextStatement* stmt) {
-}
-
-
void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
// Switch statements breakable if the tag expression is.
Visit(stmt->tag());
@@ -190,9 +185,9 @@ void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is
// breakable.
- Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+ VariableProxy* proxy = expr->target()->AsVariableProxy();
Property* prop = expr->target()->AsProperty();
- if (prop != NULL || (var != NULL && var->is_global())) {
+ if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
is_breakable_ = true;
return;
}
@@ -291,11 +286,13 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
}
unsigned table_offset = cgen.EmitStackCheckTable();
- Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
+ Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
code->set_optimizable(info->IsOptimizable());
cgen.PopulateDeoptimizationData(code);
code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
+ code->set_has_debug_break_slots(
+ info->isolate()->debugger()->IsDebuggerActive());
code->set_allow_osr_at_loop_nesting_level(0);
code->set_stack_check_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
@@ -395,26 +392,6 @@ void FullCodeGenerator::RecordStackCheck(int ast_id) {
}
-int FullCodeGenerator::SlotOffset(Slot* slot) {
- ASSERT(slot != NULL);
- // Offset is negative because higher indexes are at lower addresses.
- int offset = -slot->index() * kPointerSize;
- // Adjust by a (parameter or local) base offset.
- switch (slot->type()) {
- case Slot::PARAMETER:
- offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
- break;
- case Slot::LOCAL:
- offset += JavaScriptFrameConstants::kLocal0Offset;
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- UNREACHABLE();
- }
- return offset;
-}
-
-
bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
// Inline smi case inside loops, but not division and modulo which
// are too complicated and take up too much space.
@@ -529,34 +506,21 @@ void FullCodeGenerator::DoTest(const TestContext* context) {
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
- int globals = 0;
+ int global_count = 0;
for (int i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
- Slot* slot = var->AsSlot();
-
- // If it was not possible to allocate the variable at compile
- // time, we need to "declare" it at runtime to make sure it
- // actually exists in the local context.
- if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
- VisitDeclaration(decl);
- } else {
- // Count global variables and functions for later processing
- globals++;
- }
+ EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count);
}
- // Compute array of global variable and function declarations.
- // Do nothing in case of no declared global functions or variables.
- if (globals > 0) {
+ // Batch declare global functions and variables.
+ if (global_count > 0) {
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(2 * globals, TENURED);
+ isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
- Slot* slot = var->AsSlot();
- if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
+ if (var->IsUnallocated()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
@@ -578,12 +542,21 @@ void FullCodeGenerator::VisitDeclarations(
}
}
// Invoke the platform-dependent code generator to do the actual
- // declaration the global variables and functions.
+ // declaration the global functions and variables.
DeclareGlobals(array);
}
}
+int FullCodeGenerator::DeclareGlobalsFlags() {
+ int flags = 0;
+ if (is_eval()) flags |= kDeclareGlobalsEvalFlag;
+ if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag;
+ if (is_native()) flags |= kDeclareGlobalsNativeFlag;
+ return flags;
+}
+
+
void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
CodeGenerator::RecordPositions(masm_, fun->start_position());
}
@@ -842,10 +815,11 @@ void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
- Breakable nested_statement(this, stmt);
+ NestedBlock nested_block(this, stmt);
SetStatementPosition(stmt);
Scope* saved_scope = scope();
+ // Push a block context when entering a block with block scoped variables.
if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope();
@@ -862,8 +836,16 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements());
scope_ = saved_scope;
- __ bind(nested_statement.break_label());
+ __ bind(nested_block.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+
+ // Pop block context if necessary.
+ if (stmt->block_scope() != NULL) {
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ // Update local stack frame context field.
+ StoreToFrameField(StandardFrameConstants::kContextOffset,
+ context_register());
+ }
}
@@ -1004,17 +986,6 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
}
-void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) {
- Comment cmnt(masm_, "[ ExitContextStatement");
- SetStatementPosition(stmt);
-
- // Pop context.
- LoadContextField(context_register(), Context::PREVIOUS_INDEX);
- // Update local stack frame context field.
- StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
-}
-
-
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
SetStatementPosition(stmt);
@@ -1162,6 +1133,9 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
{ WithOrCatch body(this);
Visit(stmt->catch_block());
}
+ // Restore the context.
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
scope_ = saved_scope;
__ jmp(&done);
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 0ed26a14..803c6187 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -191,6 +191,22 @@ class FullCodeGenerator: public AstVisitor {
Label continue_label_;
};
+ // A nested block statement.
+ class NestedBlock : public Breakable {
+ public:
+ NestedBlock(FullCodeGenerator* codegen, Block* block)
+ : Breakable(codegen, block) {
+ }
+ virtual ~NestedBlock() {}
+
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ if (statement()->AsBlock()->block_scope() != NULL) {
+ ++(*context_length);
+ }
+ return previous_;
+ };
+ };
+
// The try block of a try/catch statement.
class TryCatch : public NestedStatement {
public:
@@ -288,10 +304,6 @@ class FullCodeGenerator: public AstVisitor {
// with a GC-safe value.
void ClearAccumulator();
- // Compute the frame pointer relative offset for a given local or
- // parameter slot.
- int SlotOffset(Slot* slot);
-
// Determine whether or not to inline the smi case for the given
// operation.
bool ShouldInlineSmiCase(Token::Value op);
@@ -321,13 +333,29 @@ class FullCodeGenerator: public AstVisitor {
Label* fall_through);
#endif // V8_TARGET_ARCH_MIPS
- void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
- void Move(Register dst, Slot* source);
-
- // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
- // May emit code to traverse the context chain, destroying the scratch
- // register.
- MemOperand EmitSlotSearch(Slot* slot, Register scratch);
+ // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
+ // a register. Emits a context chain walk if if necessary (so does
+ // SetVar) so avoid calling both on the same variable.
+ void GetVar(Register destination, Variable* var);
+
+ // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in
+ // the context, the write barrier will be emitted and source, scratch0,
+ // scratch1 will be clobbered. Emits a context chain walk if if necessary
+ // (so does GetVar) so avoid calling both on the same variable.
+ void SetVar(Variable* var,
+ Register source,
+ Register scratch0,
+ Register scratch1);
+
+ // An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
+ // variable. Writing does not need the write barrier.
+ MemOperand StackOperand(Variable* var);
+
+ // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
+ // variable. May emit code to traverse the context chain, loading the
+ // found context into the scratch register. Writing to this operand will
+ // need the write barrier if location is CONTEXT.
+ MemOperand VarOperand(Variable* var, Register scratch);
// Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context).
@@ -358,6 +386,7 @@ class FullCodeGenerator: public AstVisitor {
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs);
+ int DeclareGlobalsFlags();
// Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations
@@ -402,9 +431,10 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific code for a variable, constant, or function
// declaration. Functions have an initial value.
- void EmitDeclaration(Variable* variable,
+ void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function);
+ FunctionLiteral* function,
+ int* global_count);
// Platform-specific code for checking the stack limit at the back edge of
// a loop.
@@ -435,14 +465,14 @@ class FullCodeGenerator: public AstVisitor {
#undef EMIT_INLINE_RUNTIME_CALL
// Platform-specific code for loading variables.
- void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
- TypeofState typeof_state,
- Label* slow);
- MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
- void EmitDynamicLoadFromSlotFastCase(Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done);
+ void EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow);
+ MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
+ void EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done);
void EmitVariableLoad(VariableProxy* proxy);
enum ResolveEvalFlag {
@@ -555,6 +585,7 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
+ bool is_native() { return info_->is_native(); }
bool is_strict_mode() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() {
return is_strict_mode() ? kStrictMode : kNonStrictMode;
@@ -618,11 +649,11 @@ class FullCodeGenerator: public AstVisitor {
// this expression context.
virtual void Plug(bool flag) const = 0;
- // Emit code to convert a pure value (in a register, slot, as a literal,
- // or on top of the stack) into the result expected according to this
- // expression context.
+ // Emit code to convert a pure value (in a register, known variable
+ // location, as a literal, or on top of the stack) into the result
+ // expected according to this expression context.
virtual void Plug(Register reg) const = 0;
- virtual void Plug(Slot* slot) const = 0;
+ virtual void Plug(Variable* var) const = 0;
virtual void Plug(Handle<Object> lit) const = 0;
virtual void Plug(Heap::RootListIndex index) const = 0;
virtual void PlugTOS() const = 0;
@@ -680,7 +711,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -703,7 +734,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -744,7 +775,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -774,7 +805,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 4d57e254..68cb0533 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -993,7 +993,7 @@ class CodeDescription BASE_EMBEDDED {
}
#endif
- SmartPointer<char> GetFilename() {
+ SmartArrayPointer<char> GetFilename() {
return String::cast(script_->name())->ToCString();
}
@@ -1991,7 +1991,7 @@ void GDBJITInterface::AddCode(Handle<String> name,
GetScriptLineNumber(script, 0);
if (!name.is_null()) {
- SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS);
AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script, info);
} else {
AddCode("", *code, GDBJITInterface::FUNCTION, *script, info);
diff --git a/src/globals.h b/src/globals.h
index 7e41f976..6c6966ae 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -28,6 +28,35 @@
#ifndef V8_GLOBALS_H_
#define V8_GLOBALS_H_
+// Define V8_INFINITY
+#define V8_INFINITY INFINITY
+
+// GCC specific stuff
+#ifdef __GNUC__
+
+#define __GNUC_VERSION_FOR_INFTY__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
+
+// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
+// warning flag and certain versions of GCC due to a bug:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
+// For now, we use the more involved template-based version from <limits>, but
+// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
+// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
+#if __GNUC_VERSION_FOR_INFTY__ >= 29600 && __GNUC_VERSION_FOR_INFTY__ < 40100
+#include <limits>
+#undef V8_INFINITY
+#define V8_INFINITY std::numeric_limits<double>::infinity()
+#endif
+#undef __GNUC_VERSION_FOR_INFTY__
+
+#endif // __GNUC__
+
+#ifdef _MSC_VER
+#undef V8_INFINITY
+#define V8_INFINITY HUGE_VAL
+#endif
+
+
#include "../include/v8stdint.h"
namespace v8 {
@@ -226,10 +255,6 @@ const int kBinary32MinExponent = 0x01;
const int kBinary32MantissaBits = 23;
const int kBinary32ExponentShift = 23;
-// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
-// other bits set.
-const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
-
// ASCII/UC16 constants
// Code-point values in Unicode 4.0 are 21 bits wide.
typedef uint16_t uc16;
diff --git a/src/handles.cc b/src/handles.cc
index 8c6439b2..35c363c1 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -921,16 +921,13 @@ bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
}
-static bool CompileLazyFunction(Handle<JSFunction> function,
- ClearExceptionFlag flag,
- InLoopFlag in_loop_flag) {
+bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
bool result = true;
if (function->shared()->is_compiled()) {
function->ReplaceCode(function->shared()->code());
function->shared()->set_code_age(0);
} else {
CompilationInfo info(function);
- if (in_loop_flag == IN_LOOP) info.MarkAsInLoop();
result = CompileLazyHelper(&info, flag);
ASSERT(!result || function->is_compiled());
}
@@ -938,18 +935,6 @@ static bool CompileLazyFunction(Handle<JSFunction> function,
}
-bool CompileLazy(Handle<JSFunction> function,
- ClearExceptionFlag flag) {
- return CompileLazyFunction(function, flag, NOT_IN_LOOP);
-}
-
-
-bool CompileLazyInLoop(Handle<JSFunction> function,
- ClearExceptionFlag flag) {
- return CompileLazyFunction(function, flag, IN_LOOP);
-}
-
-
bool CompileOptimized(Handle<JSFunction> function,
int osr_ast_id,
ClearExceptionFlag flag) {
diff --git a/src/handles.h b/src/handles.h
index 9bb3b1f1..7eaf4de9 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -363,8 +363,6 @@ bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
-bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
-
bool CompileOptimized(Handle<JSFunction> function,
int osr_ast_id,
ClearExceptionFlag flag);
diff --git a/src/heap.cc b/src/heap.cc
index 279f30b4..d0185930 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -41,7 +41,6 @@
#include "natives.h"
#include "objects-visiting.h"
#include "runtime-profiler.h"
-#include "scanner-base.h"
#include "scopeinfo.h"
#include "snapshot.h"
#include "v8threads.h"
@@ -70,11 +69,11 @@ Heap::Heap()
: isolate_(NULL),
// semispace_size_ should be a power of 2 and old_generation_size_ should be
// a multiple of Page::kPageSize.
-#if 0//defined(ANDROID)
+#if defined(ANDROID)
reserved_semispace_size_(2*MB),
max_semispace_size_(2*MB),
initial_semispace_size_(128*KB),
- max_old_generation_size_(512*MB),
+ max_old_generation_size_(192*MB),
max_executable_size_(max_old_generation_size_),
code_range_size_(0),
#elif defined(V8_TARGET_ARCH_X64)
@@ -842,6 +841,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
isolate_->keyed_lookup_cache()->Clear();
isolate_->context_slot_cache()->Clear();
isolate_->descriptor_lookup_cache()->Clear();
+ StringSplitCache::Clear(string_split_cache());
isolate_->compilation_cache()->MarkCompactPrologue();
@@ -1627,7 +1627,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
- map->set_elements_kind(JSObject::FAST_ELEMENTS);
+ map->set_elements_kind(FAST_ELEMENTS);
// If the map object is aligned fill the padding area with Smi 0 objects.
if (Map::kPadStart < Map::kSize) {
@@ -2223,6 +2223,13 @@ bool Heap::CreateInitialObjects() {
}
set_single_character_string_cache(FixedArray::cast(obj));
+ // Allocate cache for string split.
+ { MaybeObject* maybe_obj =
+ AllocateFixedArray(StringSplitCache::kStringSplitCacheSize, TENURED);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_string_split_cache(FixedArray::cast(obj));
+
// Allocate cache for external strings pointing to native source code.
{ MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
if (!maybe_obj->ToObject(&obj)) return false;
@@ -2248,6 +2255,75 @@ bool Heap::CreateInitialObjects() {
}
+Object* StringSplitCache::Lookup(
+ FixedArray* cache, String* string, String* pattern) {
+ if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0);
+ uint32_t hash = string->Hash();
+ uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
+ ~(kArrayEntriesPerCacheEntry - 1));
+ if (cache->get(index + kStringOffset) == string &&
+ cache->get(index + kPatternOffset) == pattern) {
+ return cache->get(index + kArrayOffset);
+ }
+ index = ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+ if (cache->get(index + kStringOffset) == string &&
+ cache->get(index + kPatternOffset) == pattern) {
+ return cache->get(index + kArrayOffset);
+ }
+ return Smi::FromInt(0);
+}
+
+
+void StringSplitCache::Enter(Heap* heap,
+ FixedArray* cache,
+ String* string,
+ String* pattern,
+ FixedArray* array) {
+ if (!string->IsSymbol() || !pattern->IsSymbol()) return;
+ uint32_t hash = string->Hash();
+ uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
+ ~(kArrayEntriesPerCacheEntry - 1));
+ if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
+ cache->set(index + kStringOffset, string);
+ cache->set(index + kPatternOffset, pattern);
+ cache->set(index + kArrayOffset, array);
+ } else {
+ uint32_t index2 =
+ ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+ if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
+ cache->set(index2 + kStringOffset, string);
+ cache->set(index2 + kPatternOffset, pattern);
+ cache->set(index2 + kArrayOffset, array);
+ } else {
+ cache->set(index2 + kStringOffset, Smi::FromInt(0));
+ cache->set(index2 + kPatternOffset, Smi::FromInt(0));
+ cache->set(index2 + kArrayOffset, Smi::FromInt(0));
+ cache->set(index + kStringOffset, string);
+ cache->set(index + kPatternOffset, pattern);
+ cache->set(index + kArrayOffset, array);
+ }
+ }
+ if (array->length() < 100) { // Limit how many new symbols we want to make.
+ for (int i = 0; i < array->length(); i++) {
+ String* str = String::cast(array->get(i));
+ Object* symbol;
+ MaybeObject* maybe_symbol = heap->LookupSymbol(str);
+ if (maybe_symbol->ToObject(&symbol)) {
+ array->set(i, symbol);
+ }
+ }
+ }
+ array->set_map(heap->fixed_cow_array_map());
+}
+
+
+void StringSplitCache::Clear(FixedArray* cache) {
+ for (int i = 0; i < kStringSplitCacheSize; i++) {
+ cache->set(i, Smi::FromInt(0));
+ }
+}
+
+
MaybeObject* Heap::InitializeNumberStringCache() {
// Compute the size of the number string cache based on the max heap size.
// max_semispace_size_ == 512 KB => number_string_cache_size = 32.
@@ -3339,11 +3415,36 @@ MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
map->set_prototype(prototype);
// Allocate the proxy object.
- Object* result;
+ JSProxy* result;
MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- JSProxy::cast(result)->set_handler(handler);
- JSProxy::cast(result)->set_padding(Smi::FromInt(0));
+ if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
+ result->InitializeBody(map->instance_size(), Smi::FromInt(0));
+ result->set_handler(handler);
+ return result;
+}
+
+
+MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
+ Object* call_trap,
+ Object* construct_trap,
+ Object* prototype) {
+ // Allocate map.
+ // TODO(rossberg): Once we optimize proxies, think about a scheme to share
+ // maps. Will probably depend on the identity of the handler object, too.
+ Map* map;
+ MaybeObject* maybe_map_obj =
+ AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
+ if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
+ map->set_prototype(prototype);
+
+ // Allocate the proxy object.
+ JSFunctionProxy* result;
+ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
+ if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
+ result->InitializeBody(map->instance_size(), Smi::FromInt(0));
+ result->set_handler(handler);
+ result->set_call_trap(call_trap);
+ result->set_construct_trap(construct_trap);
return result;
}
@@ -3488,16 +3589,19 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
}
-MaybeObject* Heap::ReinitializeJSProxyAsJSObject(JSProxy* object) {
+MaybeObject* Heap::ReinitializeJSReceiver(
+ JSReceiver* object, InstanceType type, int size) {
+ ASSERT(type >= FIRST_JS_RECEIVER_TYPE);
+
// Allocate fresh map.
// TODO(rossberg): Once we optimize proxies, cache these maps.
Map* map;
- MaybeObject* maybe_map_obj =
- AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ MaybeObject* maybe_map_obj = AllocateMap(type, size);
if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
- // Check that the receiver has the same size as a fresh object.
- ASSERT(map->instance_size() == object->map()->instance_size());
+ // Check that the receiver has at least the size of the fresh object.
+ int size_difference = object->map()->instance_size() - map->instance_size();
+ ASSERT(size_difference >= 0);
map->set_prototype(object->map()->prototype());
@@ -3514,6 +3618,28 @@ MaybeObject* Heap::ReinitializeJSProxyAsJSObject(JSProxy* object) {
// Reinitialize the object from the constructor map.
InitializeJSObjectFromMap(JSObject::cast(object),
FixedArray::cast(properties), map);
+
+ // Functions require some minimal initialization.
+ if (type == JS_FUNCTION_TYPE) {
+ String* name;
+ MaybeObject* maybe_name = LookupAsciiSymbol("<freezing call trap>");
+ if (!maybe_name->To<String>(&name)) return maybe_name;
+ SharedFunctionInfo* shared;
+ MaybeObject* maybe_shared = AllocateSharedFunctionInfo(name);
+ if (!maybe_shared->To<SharedFunctionInfo>(&shared)) return maybe_shared;
+ JSFunction* func;
+ MaybeObject* maybe_func =
+ InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
+ if (!maybe_func->To<JSFunction>(&func)) return maybe_func;
+ func->set_context(isolate()->context()->global_context());
+ }
+
+ // Put in filler if the new object is smaller than the old.
+ if (size_difference > 0) {
+ CreateFillerObjectAt(
+ object->address() + map->instance_size(), size_difference);
+ }
+
return object;
}
@@ -3546,6 +3672,9 @@ MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
PretenureFlag pretenure) {
+ if (string.length() == 1) {
+ return Heap::LookupSingleCharacterStringFromCode(string[0]);
+ }
Object* result;
{ MaybeObject* maybe_result =
AllocateRawAsciiString(string.length(), pretenure);
diff --git a/src/heap.h b/src/heap.h
index 0f69fab3..d81ff6ca 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -77,6 +77,7 @@ inline Heap* _inline_get_heap_();
V(Object, instanceof_cache_map, InstanceofCacheMap) \
V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
+ V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \
@@ -225,8 +226,7 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
V(dot_symbol, ".") \
- V(anonymous_function_symbol, "(anonymous function)") \
- V(block_scope_symbol, ".block")
+ V(anonymous_function_symbol, "(anonymous function)")
// Forward declarations.
class GCTracer;
@@ -440,17 +440,25 @@ class Heap {
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateFunctionPrototype(JSFunction* function);
- // Allocates a Harmony Proxy.
+ // Allocates a Harmony proxy or function proxy.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler,
Object* prototype);
- // Reinitialize a JSProxy into an (empty) JSObject. The receiver
- // must have the same size as an empty object. The object is reinitialized
- // and behaves as an object that has been freshly allocated.
- MUST_USE_RESULT MaybeObject* ReinitializeJSProxyAsJSObject(JSProxy* object);
+ MUST_USE_RESULT MaybeObject* AllocateJSFunctionProxy(Object* handler,
+ Object* call_trap,
+ Object* construct_trap,
+ Object* prototype);
+
+ // Reinitialize a JSReceiver into an (empty) JS object of respective type and
+ // size, but keeping the original prototype. The receiver must have at least
+ // the size of the new object. The object is reinitialized and behaves as an
+ // object that has been freshly allocated.
+ MUST_USE_RESULT MaybeObject* ReinitializeJSReceiver(JSReceiver* object,
+ InstanceType type,
+ int size);
// Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the
@@ -2177,6 +2185,27 @@ class GCTracer BASE_EMBEDDED {
};
+class StringSplitCache {
+ public:
+ static Object* Lookup(FixedArray* cache, String* string, String* pattern);
+ static void Enter(Heap* heap,
+ FixedArray* cache,
+ String* string,
+ String* pattern,
+ FixedArray* array);
+ static void Clear(FixedArray* cache);
+ static const int kStringSplitCacheSize = 0x100;
+
+ private:
+ static const int kArrayEntriesPerCacheEntry = 4;
+ static const int kStringOffset = 0;
+ static const int kPatternOffset = 1;
+ static const int kArrayOffset = 2;
+
+ static MaybeObject* WrapFixedArrayInJSArray(Object* fixed_array);
+};
+
+
class TranscendentalCache {
public:
enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index d3cc8a62..5630ce39 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -425,7 +425,7 @@ void HValue::PrintRangeTo(StringStream* stream) {
void HValue::PrintChangesTo(StringStream* stream) {
- int changes_flags = (flags() & HValue::ChangesFlagsMask());
+ int changes_flags = ChangesFlags();
if (changes_flags == 0) return;
stream->Add(" changes[");
if (changes_flags == AllSideEffects()) {
@@ -512,9 +512,7 @@ void HInstruction::PrintTo(StringStream* stream) {
void HInstruction::PrintMnemonicTo(StringStream* stream) {
- stream->Add("%s", Mnemonic());
- if (HasSideEffects()) stream->Add("*");
- stream->Add(" ");
+ stream->Add("%s ", Mnemonic());
}
@@ -791,6 +789,13 @@ void HChange::PrintDataTo(StringStream* stream) {
}
+void HJSArrayLength::PrintDataTo(StringStream* stream) {
+ value()->PrintNameTo(stream);
+ stream->Add(" ");
+ typecheck()->PrintNameTo(stream);
+}
+
+
HValue* HCheckInstanceType::Canonicalize() {
if (check_ == IS_STRING &&
!value()->type().IsUninitialized() &&
@@ -1020,11 +1025,14 @@ void HPhi::PrintTo(StringStream* stream) {
value->PrintNameTo(stream);
stream->Add(" ");
}
- stream->Add(" uses%d_%di_%dd_%dt]",
+ stream->Add(" uses%d_%di_%dd_%dt",
UseCount(),
int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses());
+ stream->Add("%s%s]",
+ is_live() ? "_live" : "",
+ IsConvertibleToInteger() ? "" : "_ncti");
}
@@ -1125,7 +1133,7 @@ void HDeoptimize::PrintDataTo(StringStream* stream) {
void HEnterInlined::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name = function()->debug_name()->ToCString();
+ SmartArrayPointer<char> name = function()->debug_name()->ToCString();
stream->Add("%s, id=%d", *name, function()->id());
}
@@ -1299,6 +1307,12 @@ void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
left()->PrintNameTo(stream);
stream->Add(" ");
right()->PrintNameTo(stream);
+ HControlInstruction::PrintDataTo(stream);
+}
+
+
+void HGoto::PrintDataTo(StringStream* stream) {
+ stream->Add("B%d", SuccessorAt(0)->block_id());
}
@@ -1446,37 +1460,37 @@ void HLoadKeyedSpecializedArrayElement::PrintDataTo(
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (elements_kind()) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
stream->Add("byte");
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
stream->Add("u_byte");
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
stream->Add("short");
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
stream->Add("u_short");
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
stream->Add("int");
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
stream->Add("u_int");
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
stream->Add("float");
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
stream->Add("double");
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -1541,37 +1555,37 @@ void HStoreKeyedSpecializedArrayElement::PrintDataTo(
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (elements_kind()) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
stream->Add("byte");
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
stream->Add("u_byte");
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
stream->Add("short");
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
stream->Add("u_short");
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
stream->Add("int");
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
stream->Add("u_int");
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
stream->Add("float");
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
stream->Add("double");
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 76007d76..1bc28ba8 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -513,19 +513,6 @@ class HValue: public ZoneObject {
static const int kChangesToDependsFlagsLeftShift = 1;
- static int ChangesFlagsMask() {
- int result = 0;
- // Create changes mask.
-#define DECLARE_DO(type) result |= (1 << kChanges##type);
- GVN_FLAG_LIST(DECLARE_DO)
-#undef DECLARE_DO
- return result;
- }
-
- static int DependsFlagsMask() {
- return ConvertChangesToDependsFlags(ChangesFlagsMask());
- }
-
static int ConvertChangesToDependsFlags(int flags) {
return flags << kChangesToDependsFlagsLeftShift;
}
@@ -629,6 +616,8 @@ class HValue: public ZoneObject {
void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); }
bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; }
+ int ChangesFlags() const { return flags_ & ChangesFlagsMask(); }
+
Range* range() const { return range_; }
bool HasRange() const { return range_ != NULL; }
void AddNewRange(Range* r);
@@ -693,6 +682,15 @@ class HValue: public ZoneObject {
}
private:
+ static int ChangesFlagsMask() {
+ int result = 0;
+ // Create changes mask.
+#define ADD_FLAG(type) result |= (1 << kChanges##type);
+ GVN_FLAG_LIST(ADD_FLAG)
+#undef ADD_FLAG
+ return result;
+ }
+
// A flag mask to mark an instruction as having arbitrary side effects.
static int AllSideEffects() {
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
@@ -917,6 +915,8 @@ class HGoto: public HTemplateControlInstruction<1, 0> {
return Representation::None();
}
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(Goto)
};
@@ -1696,7 +1696,10 @@ class HJSArrayLength: public HTemplateInstruction<2> {
return Representation::Tagged();
}
+ virtual void PrintDataTo(StringStream* stream);
+
HValue* value() { return OperandAt(0); }
+ HValue* typecheck() { return OperandAt(1); }
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
@@ -2208,6 +2211,13 @@ class HPhi: public HValue {
is_convertible_to_integer_ = b;
}
+ bool AllOperandsConvertibleToInteger() {
+ for (int i = 0; i < OperandCount(); ++i) {
+ if (!OperandAt(i)->IsConvertibleToInteger()) return false;
+ }
+ return true;
+ }
+
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -3554,12 +3564,12 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: elements_kind_(elements_kind) {
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
set_representation(Representation::Double());
} else {
set_representation(Representation::Integer32());
@@ -3582,7 +3592,7 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
- JSObject::ElementsKind elements_kind() const { return elements_kind_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
@@ -3595,7 +3605,7 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
}
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
};
@@ -3775,7 +3785,7 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
HValue* val,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: elements_kind_(elements_kind) {
SetFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
@@ -3790,8 +3800,8 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
return Representation::External();
} else {
bool float_or_double_elements =
- elements_kind() == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind() == JSObject::EXTERNAL_DOUBLE_ELEMENTS;
+ elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
if (index == 2 && float_or_double_elements) {
return Representation::Double();
} else {
@@ -3803,12 +3813,12 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
- JSObject::ElementsKind elements_kind() const { return elements_kind_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 5772141b..c625fba8 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -220,6 +220,17 @@ bool HBasicBlock::Dominates(HBasicBlock* other) const {
}
+int HBasicBlock::LoopNestingDepth() const {
+ const HBasicBlock* current = this;
+ int result = (current->IsLoopHeader()) ? 1 : 0;
+ while (current->parent_loop_header() != NULL) {
+ current = current->parent_loop_header();
+ result++;
+ }
+ return result;
+}
+
+
void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
ASSERT(IsLoopHeader());
@@ -638,8 +649,7 @@ Handle<Code> HGraph::Compile(CompilationInfo* info) {
PrintF("Crankshaft Compiler - ");
}
CodeGenerator::MakeCodePrologue(info);
- Code::Flags flags =
- Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP);
+ Code::Flags flags = Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
Handle<Code> code =
CodeGenerator::MakeCodeEpilogue(&assembler, flags, info);
generator.FinishCode(code);
@@ -840,7 +850,7 @@ void HGraph::EliminateUnreachablePhis() {
}
-bool HGraph::CheckArgumentsPhiUses() {
+bool HGraph::CheckPhis() {
int block_count = blocks_.length();
for (int i = 0; i < block_count; ++i) {
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
@@ -853,11 +863,13 @@ bool HGraph::CheckArgumentsPhiUses() {
}
-bool HGraph::CheckConstPhiUses() {
+bool HGraph::CollectPhis() {
int block_count = blocks_.length();
+ phi_list_ = new ZoneList<HPhi*>(block_count);
for (int i = 0; i < block_count; ++i) {
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
HPhi* phi = blocks_[i]->phis()->at(j);
+ phi_list_->Add(phi);
// Check for the hole value (from an uninitialized const).
for (int k = 0; k < phi->OperandCount(); k++) {
if (phi->OperandAt(k) == GetConstantHole()) return false;
@@ -868,18 +880,6 @@ bool HGraph::CheckConstPhiUses() {
}
-void HGraph::CollectPhis() {
- int block_count = blocks_.length();
- phi_list_ = new ZoneList<HPhi*>(block_count);
- for (int i = 0; i < block_count; ++i) {
- for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
- HPhi* phi = blocks_[i]->phis()->at(j);
- phi_list_->Add(phi);
- }
- }
-}
-
-
void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
BitVector in_worklist(GetMaximumValueID());
for (int i = 0; i < worklist->length(); ++i) {
@@ -1392,7 +1392,7 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() {
int id = block->block_id();
int side_effects = 0;
while (instr != NULL) {
- side_effects |= (instr->flags() & HValue::ChangesFlagsMask());
+ side_effects |= instr->ChangesFlags();
instr = instr->next();
}
block_side_effects_[id] |= side_effects;
@@ -1512,7 +1512,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
HInstruction* instr = block->first();
while (instr != NULL) {
HInstruction* next = instr->next();
- int flags = (instr->flags() & HValue::ChangesFlagsMask());
+ int flags = instr->ChangesFlags();
if (flags != 0) {
ASSERT(!instr->CheckFlag(HValue::kUseGVN));
// Clear all instructions in the map that are affected by side effects.
@@ -1651,18 +1651,20 @@ Representation HInferRepresentation::TryChange(HValue* value) {
int non_tagged_count = double_count + int32_count;
// If a non-loop phi has tagged uses, don't convert it to untagged.
- if (value->IsPhi() && !value->block()->IsLoopHeader()) {
- if (tagged_count > 0) return Representation::None();
+ if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) {
+ return Representation::None();
}
- if (non_tagged_count >= tagged_count) {
- if (int32_count > 0) {
- if (!value->IsPhi() || value->IsConvertibleToInteger()) {
- return Representation::Integer32();
- }
- }
- if (double_count > 0) return Representation::Double();
+ // Prefer unboxing over boxing, the latter is more expensive.
+ if (tagged_count > non_tagged_count) Representation::None();
+
+ // Prefer Integer32 over Double, if possible.
+ if (int32_count > 0 && value->IsConvertibleToInteger()) {
+ return Representation::Integer32();
}
+
+ if (double_count > 0) return Representation::Double();
+
return Representation::None();
}
@@ -1688,7 +1690,9 @@ void HInferRepresentation::Analyze() {
bool change = true;
while (change) {
change = false;
- for (int i = 0; i < phi_count; ++i) {
+ // We normally have far more "forward edges" than "backward edges",
+ // so we terminate faster when we walk backwards.
+ for (int i = phi_count - 1; i >= 0; --i) {
HPhi* phi = phi_list->at(i);
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
@@ -1701,40 +1705,25 @@ void HInferRepresentation::Analyze() {
}
}
- // (3) Sum up the non-phi use counts of all connected phis. Don't include
- // the non-phi uses of the phi itself.
+ // (3) Use the phi reachability information from step 2 to
+ // (a) sum up the non-phi use counts of all connected phis.
+ // (b) push information about values which can't be converted to integer
+ // without deoptimization through the phi use-def chains, avoiding
+ // unnecessary deoptimizations later.
for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
+ bool cti = phi->AllOperandsConvertibleToInteger();
for (BitVector::Iterator it(connected_phis.at(i));
!it.Done();
it.Advance()) {
int index = it.Current();
- if (index != i) {
- HPhi* it_use = phi_list->at(it.Current());
- phi->AddNonPhiUsesFrom(it_use);
- }
- }
- }
-
- // (4) Compute phis that definitely can't be converted to integer
- // without deoptimization and mark them to avoid unnecessary deoptimization.
- change = true;
- while (change) {
- change = false;
- for (int i = 0; i < phi_count; ++i) {
- HPhi* phi = phi_list->at(i);
- for (int j = 0; j < phi->OperandCount(); ++j) {
- if (phi->IsConvertibleToInteger() &&
- !phi->OperandAt(j)->IsConvertibleToInteger()) {
- phi->set_is_convertible_to_integer(false);
- change = true;
- break;
- }
- }
+ HPhi* it_use = phi_list->at(it.Current());
+ if (index != i) phi->AddNonPhiUsesFrom(it_use); // Don't count twice!
+ if (!cti) it_use->set_is_convertible_to_integer(false);
}
}
-
+ // Initialize work list
for (int i = 0; i < graph_->blocks()->length(); ++i) {
HBasicBlock* block = graph_->blocks()->at(i);
const ZoneList<HPhi*>* phis = block->phis();
@@ -1749,6 +1738,7 @@ void HInferRepresentation::Analyze() {
}
}
+ // Do a fixed point iteration, trying to improve representations
while (!worklist_.is_empty()) {
HValue* current = worklist_.RemoveLast();
in_worklist_.Remove(current->id());
@@ -2214,7 +2204,8 @@ void TestContext::BuildBranch(HValue* value) {
void HGraphBuilder::Bailout(const char* reason) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
}
SetStackOverflow();
@@ -2286,10 +2277,6 @@ HGraph* HGraphBuilder::CreateGraph() {
return NULL;
}
SetupScope(scope);
- VisitDeclarations(scope->declarations());
- HValue* context = environment()->LookupContext();
- AddInstruction(
- new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
// Add an edge to the body entry. This is warty: the graph's start
// environment will be used by the Lithium translation as the initial
@@ -2311,6 +2298,19 @@ HGraph* HGraphBuilder::CreateGraph() {
current_block()->Goto(body_entry);
body_entry->SetJoinId(AstNode::kFunctionEntryId);
set_current_block(body_entry);
+
+ // Handle implicit declaration of the function name in named function
+ // expressions before other declarations.
+ if (scope->is_function_scope() && scope->function() != NULL) {
+ HandleDeclaration(scope->function(), Variable::CONST, NULL);
+ }
+ VisitDeclarations(scope->declarations());
+ AddSimulate(AstNode::kDeclarationsId);
+
+ HValue* context = environment()->LookupContext();
+ AddInstruction(
+ new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
+
VisitStatements(info()->function()->body());
if (HasStackOverflow()) return NULL;
@@ -2324,17 +2324,16 @@ HGraph* HGraphBuilder::CreateGraph() {
graph()->OrderBlocks();
graph()->AssignDominators();
graph()->PropagateDeoptimizingMark();
- if (!graph()->CheckConstPhiUses()) {
- Bailout("Unsupported phi use of const variable");
- return NULL;
- }
graph()->EliminateRedundantPhis();
- if (!graph()->CheckArgumentsPhiUses()) {
- Bailout("Unsupported phi use of arguments");
+ if (!graph()->CheckPhis()) {
+ Bailout("Unsupported phi use of arguments object");
return NULL;
}
if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
- graph()->CollectPhis();
+ if (!graph()->CollectPhis()) {
+ Bailout("Unsupported phi use of uninitialized constant");
+ return NULL;
+ }
HInferRepresentation rep(graph());
rep.Analyze();
@@ -2465,14 +2464,6 @@ void HGraphBuilder::SetupScope(Scope* scope) {
graph()->SetArgumentsObject(object);
environment()->Bind(scope->arguments(), object);
}
- // Handle implicit declaration of the function name in named function
- // expressions before other declarations.
- if (scope->is_function_scope() && scope->function() != NULL) {
- if (!scope->function()->IsStackAllocated()) {
- return Bailout("unsupported declaration");
- }
- environment()->Bind(scope->function(), graph()->GetConstantHole());
- }
}
@@ -2665,14 +2656,6 @@ void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
}
-void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
- ASSERT(!HasStackOverflow());
- ASSERT(current_block() != NULL);
- ASSERT(current_block()->HasPredecessor());
- return Bailout("ExitContextStatement");
-}
-
-
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -3141,56 +3124,63 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- Variable* variable = expr->AsVariable();
- if (variable == NULL) {
- return Bailout("reference to rewritten variable");
- } else if (variable->mode() == Variable::LET) {
+ Variable* variable = expr->var();
+ if (variable->mode() == Variable::LET) {
return Bailout("reference to let variable");
- } else if (variable->IsStackAllocated()) {
- HValue* value = environment()->Lookup(variable);
- if (variable->mode() == Variable::CONST &&
- value == graph()->GetConstantHole()) {
- return Bailout("reference to uninitialized const variable");
- }
- return ast_context()->ReturnValue(value);
- } else if (variable->IsContextSlot()) {
- if (variable->mode() == Variable::CONST) {
- return Bailout("reference to const context slot");
- }
- HValue* context = BuildContextChainWalk(variable);
- int index = variable->AsSlot()->index();
- HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index);
- return ast_context()->ReturnInstruction(instr, expr->id());
- } else if (variable->is_global()) {
- LookupResult lookup;
- GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false);
+ }
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ LookupResult lookup;
+ GlobalPropertyAccess type =
+ LookupGlobalProperty(variable, &lookup, false);
- if (type == kUseCell &&
- info()->global_object()->IsAccessCheckNeeded()) {
- type = kUseGeneric;
+ if (type == kUseCell &&
+ info()->global_object()->IsAccessCheckNeeded()) {
+ type = kUseGeneric;
+ }
+
+ if (type == kUseCell) {
+ Handle<GlobalObject> global(info()->global_object());
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
+ HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ } else {
+ HValue* context = environment()->LookupContext();
+ HGlobalObject* global_object = new(zone()) HGlobalObject(context);
+ AddInstruction(global_object);
+ HLoadGlobalGeneric* instr =
+ new(zone()) HLoadGlobalGeneric(context,
+ global_object,
+ variable->name(),
+ ast_context()->is_for_typeof());
+ instr->set_position(expr->position());
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ }
}
- if (type == kUseCell) {
- Handle<GlobalObject> global(info()->global_object());
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
- bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
- HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
- return ast_context()->ReturnInstruction(instr, expr->id());
- } else {
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- AddInstruction(global_object);
- HLoadGlobalGeneric* instr =
- new(zone()) HLoadGlobalGeneric(context,
- global_object,
- variable->name(),
- ast_context()->is_for_typeof());
- instr->set_position(expr->position());
- ASSERT(instr->HasSideEffects());
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ HValue* value = environment()->Lookup(variable);
+ if (variable->mode() == Variable::CONST &&
+ value == graph()->GetConstantHole()) {
+ return Bailout("reference to uninitialized const variable");
+ }
+ return ast_context()->ReturnValue(value);
+ }
+
+ case Variable::CONTEXT: {
+ if (variable->mode() == Variable::CONST) {
+ return Bailout("reference to const context slot");
+ }
+ HValue* context = BuildContextChainWalk(variable);
+ HLoadContextSlot* instr =
+ new(zone()) HLoadContextSlot(context, variable->index());
return ast_context()->ReturnInstruction(instr, expr->id());
}
- } else {
- return Bailout("reference to a variable which requires dynamic lookup");
+
+ case Variable::LOOKUP:
+ return Bailout("reference to a variable which requires dynamic lookup");
}
}
@@ -3602,52 +3592,61 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Expression* target = expr->target();
VariableProxy* proxy = target->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- ASSERT(var == NULL || prop == NULL);
+ ASSERT(proxy == NULL || prop == NULL);
// We have a second position recorded in the FullCodeGenerator to have
// type feedback for the binary operation.
BinaryOperation* operation = expr->binary_operation();
- if (var != NULL) {
- if (var->mode() == Variable::CONST ||
- var->mode() == Variable::LET) {
+ if (proxy != NULL) {
+ Variable* var = proxy->var();
+ if (var->mode() == Variable::CONST || var->mode() == Variable::LET) {
return Bailout("unsupported let or const compound assignment");
}
CHECK_ALIVE(VisitForValue(operation));
- if (var->is_global()) {
- HandleGlobalVariableAssignment(var,
- Top(),
- expr->position(),
- expr->AssignmentId());
- } else if (var->IsStackAllocated()) {
- Bind(var, Top());
- } else if (var->IsContextSlot()) {
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ HandleGlobalVariableAssignment(var,
+ Top(),
+ expr->position(),
+ expr->AssignmentId());
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ Bind(var, Top());
+ break;
+
+ case Variable::CONTEXT: {
+ // Bail out if we try to mutate a parameter value in a function
+ // using the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will be allocated to context slots. We have no
+ // direct way to detect that the variable is a parameter so we do
+ // a linear search of the parameter variables.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ Bailout(
+ "assignment to parameter, function uses arguments object");
+ }
}
}
+
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ break;
}
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, Top());
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- } else {
- return Bailout("compound assignment to lookup slot");
+ case Variable::LOOKUP:
+ return Bailout("compound assignment to lookup slot");
}
return ast_context()->ReturnValue(Pop());
@@ -3735,16 +3734,18 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
VariableProxy* proxy = expr->target()->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = expr->target()->AsProperty();
- ASSERT(var == NULL || prop == NULL);
+ ASSERT(proxy == NULL || prop == NULL);
if (expr->is_compound()) {
HandleCompoundAssignment(expr);
return;
}
- if (var != NULL) {
+ if (prop != NULL) {
+ HandlePropertyAssignment(expr);
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
if (var->mode() == Variable::CONST) {
if (expr->op() != Token::INIT_CONST) {
return Bailout("non-initializer assignment to const");
@@ -3763,54 +3764,54 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
if (proxy->IsArguments()) return Bailout("assignment to arguments");
// Handle the assignment.
- if (var->IsStackAllocated()) {
- // We do not allow the arguments object to occur in a context where it
- // may escape, but assignments to stack-allocated locals are
- // permitted.
- CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
- HValue* value = Pop();
- Bind(var, value);
- return ast_context()->ReturnValue(value);
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ HandleGlobalVariableAssignment(var,
+ Top(),
+ expr->position(),
+ expr->AssignmentId());
+ return ast_context()->ReturnValue(Pop());
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ // We do not allow the arguments object to occur in a context where it
+ // may escape, but assignments to stack-allocated locals are
+ // permitted.
+ CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
+ HValue* value = Pop();
+ Bind(var, value);
+ return ast_context()->ReturnValue(value);
+ }
- } else if (var->IsContextSlot()) {
- ASSERT(var->mode() != Variable::CONST);
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
+ case Variable::CONTEXT: {
+ ASSERT(var->mode() != Variable::CONST);
+ // Bail out if we try to mutate a parameter value in a function using
+ // the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will rewrite to context slots. We have no direct way
+ // to detect that the variable is a parameter.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ return Bailout("assignment to parameter in arguments object");
+ }
}
}
- }
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, Top());
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- return ast_context()->ReturnValue(Pop());
-
- } else if (var->is_global()) {
- CHECK_ALIVE(VisitForValue(expr->value()));
- HandleGlobalVariableAssignment(var,
- Top(),
- expr->position(),
- expr->AssignmentId());
- return ast_context()->ReturnValue(Pop());
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ return ast_context()->ReturnValue(Pop());
+ }
- } else {
- return Bailout("assignment to LOOKUP or const CONTEXT variable");
+ case Variable::LOOKUP:
+ return Bailout("assignment to LOOKUP variable");
}
-
- } else if (prop != NULL) {
- HandlePropertyAssignment(expr);
} else {
return Bailout("invalid left-hand side in assignment");
}
@@ -3905,35 +3906,35 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
HValue* val,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
bool is_store) {
if (is_store) {
ASSERT(val != NULL);
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
AddInstruction(clamp);
val = clamp;
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
HToInt32* floor_val = new(zone()) HToInt32(val);
AddInstruction(floor_val);
val = floor_val;
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -4017,7 +4018,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
SmallMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false;
- static const int kNumElementTypes = JSObject::kElementsKindCount;
+ static const int kNumElementTypes = kElementsKindCount;
bool type_todo[kNumElementTypes];
for (int i = 0; i < kNumElementTypes; ++i) {
type_todo[i] = false;
@@ -4027,7 +4028,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
ASSERT(maps->at(i)->IsMap());
type_todo[maps->at(i)->elements_kind()] = true;
if (maps->at(i)->elements_kind()
- >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
+ >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
todo_external_array = true;
}
}
@@ -4042,16 +4043,16 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
HInstruction* checked_key = NULL;
// FAST_ELEMENTS is assumed to be the first case.
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
- for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
- elements_kind <= JSObject::LAST_ELEMENTS_KIND;
- elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
+ for (ElementsKind elements_kind = FAST_ELEMENTS;
+ elements_kind <= LAST_ELEMENTS_KIND;
+ elements_kind = ElementsKind(elements_kind + 1)) {
// After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we
// need to add some code that's executed for all external array cases.
- STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
- JSObject::LAST_ELEMENTS_KIND);
- if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
+ STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
+ LAST_ELEMENTS_KIND);
+ if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
&& todo_external_array) {
HInstruction* length =
AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
@@ -4070,11 +4071,11 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
set_current_block(if_true);
HInstruction* access;
- if (elements_kind == JSObject::FAST_ELEMENTS ||
- elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_DOUBLE_ELEMENTS) {
bool fast_double_elements =
- elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
- if (is_store && elements_kind == JSObject::FAST_ELEMENTS) {
+ elements_kind == FAST_DOUBLE_ELEMENTS;
+ if (is_store && elements_kind == FAST_ELEMENTS) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map(),
elements_kind_branch));
@@ -4139,7 +4140,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
new(zone()) HLoadKeyedFastElement(elements, checked_key));
}
}
- } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
+ } else if (elements_kind == DICTIONARY_ELEMENTS) {
if (is_store) {
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
} else {
@@ -4434,8 +4435,10 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target,
Handle<JSFunction> caller,
const char* reason) {
if (FLAG_trace_inlining) {
- SmartPointer<char> target_name = target->shared()->DebugName()->ToCString();
- SmartPointer<char> caller_name = caller->shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> target_name =
+ target->shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> caller_name =
+ caller->shared()->DebugName()->ToCString();
if (reason == NULL) {
PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
} else {
@@ -4922,10 +4925,12 @@ void HGraphBuilder::VisitCall(Call* expr) {
}
} else {
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
- bool global_call = (var != NULL) && var->is_global() && !var->is_this();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ // FIXME.
+ bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
if (global_call) {
+ Variable* var = proxy->var();
bool known_global_function = false;
// If there is a global property cell for the name at compile time and
// access check is not enabled we assume that the function will not change
@@ -5089,20 +5094,8 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
- if (prop == NULL && var == NULL) {
- // Result of deleting non-property, non-variable reference is true.
- // Evaluate the subexpression for side effects.
- CHECK_ALIVE(VisitForEffect(expr->expression()));
- return ast_context()->ReturnValue(graph()->GetConstantTrue());
- } else if (var != NULL &&
- !var->is_global() &&
- var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- return ast_context()->ReturnValue(graph()->GetConstantFalse());
- } else if (prop != NULL) {
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ if (prop != NULL) {
CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key()));
HValue* key = Pop();
@@ -5110,10 +5103,26 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
HValue* context = environment()->LookupContext();
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
return ast_context()->ReturnInstruction(instr, expr->id());
- } else if (var->is_global()) {
- Bailout("delete with global variable");
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
+ if (var->IsUnallocated()) {
+ Bailout("delete with global variable");
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is not
+ // really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ HValue* value = var->is_this()
+ ? graph()->GetConstantTrue()
+ : graph()->GetConstantFalse();
+ return ast_context()->ReturnValue(value);
+ } else {
+ Bailout("delete with non-global variable");
+ }
} else {
- Bailout("delete with non-global variable");
+ // Result of deleting non-property, non-variable reference is true.
+ // Evaluate the subexpression for side effects.
+ CHECK_ALIVE(VisitForEffect(expr->expression()));
+ return ast_context()->ReturnValue(graph()->GetConstantTrue());
}
}
@@ -5260,9 +5269,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
ASSERT(current_block()->HasPredecessor());
Expression* target = expr->expression();
VariableProxy* proxy = target->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- if (var == NULL && prop == NULL) {
+ if (proxy == NULL && prop == NULL) {
return Bailout("invalid lhs in count operation");
}
@@ -5274,7 +5282,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* input = NULL; // ToNumber(original_input).
HValue* after = NULL; // The result after incrementing or decrementing.
- if (var != NULL) {
+ if (proxy != NULL) {
+ Variable* var = proxy->var();
if (var->mode() == Variable::CONST) {
return Bailout("unsupported count operation with const");
}
@@ -5286,36 +5295,45 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
input = returns_original_input ? Top() : Pop();
Push(after);
- if (var->is_global()) {
- HandleGlobalVariableAssignment(var,
- after,
- expr->position(),
- expr->AssignmentId());
- } else if (var->IsStackAllocated()) {
- Bind(var, after);
- } else if (var->IsContextSlot()) {
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ HandleGlobalVariableAssignment(var,
+ after,
+ expr->position(),
+ expr->AssignmentId());
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ Bind(var, after);
+ break;
+
+ case Variable::CONTEXT: {
+ // Bail out if we try to mutate a parameter value in a function
+ // using the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will rewrite to context slots. We have no direct
+ // way to detect that the variable is a parameter so we use a
+ // linear search of the parameter list.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ return Bailout("assignment to parameter in arguments object");
+ }
}
}
+
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), after);
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ break;
}
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, after);
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- } else {
- return Bailout("lookup variable in count operation");
+ case Variable::LOOKUP:
+ return Bailout("lookup variable in count operation");
}
} else {
@@ -5727,12 +5745,12 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
// residing in new space. If it is we assume that the function will stay the
// same.
Handle<JSFunction> target = Handle<JSFunction>::null();
- Variable* var = expr->right()->AsVariableProxy()->AsVariable();
- bool global_function = (var != NULL) && var->is_global() && !var->is_this();
+ VariableProxy* proxy = expr->right()->AsVariableProxy();
+ bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
if (global_function &&
info()->has_global_object() &&
!info()->global_object()->IsAccessCheckNeeded()) {
- Handle<String> name = var->name();
+ Handle<String> name = proxy->name();
Handle<GlobalObject> global(info()->global_object());
LookupResult lookup;
global->Lookup(*name, &lookup);
@@ -5831,17 +5849,42 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
void HGraphBuilder::VisitDeclaration(Declaration* decl) {
- // We support only declarations that do not require code generation.
- Variable* var = decl->proxy()->var();
- if (!var->IsStackAllocated() ||
- decl->fun() != NULL ||
- decl->mode() == Variable::LET) {
- return Bailout("unsupported declaration");
- }
-
- if (decl->mode() == Variable::CONST) {
- ASSERT(var->IsStackAllocated());
- environment()->Bind(var, graph()->GetConstantHole());
+ HandleDeclaration(decl->proxy(), decl->mode(), decl->fun());
+}
+
+
+void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* function) {
+ if (mode == Variable::LET) return Bailout("unsupported let declaration");
+ Variable* var = proxy->var();
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ return Bailout("unsupported global declaration");
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT:
+ if (mode == Variable::CONST || function != NULL) {
+ HValue* value = NULL;
+ if (mode == Variable::CONST) {
+ value = graph()->GetConstantHole();
+ } else {
+ VisitForValue(function);
+ value = Pop();
+ }
+ if (var->IsContextSlot()) {
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store =
+ new HStoreContextSlot(context, var->index(), value);
+ AddInstruction(store);
+ if (store->HasSideEffects()) AddSimulate(proxy->id());
+ } else {
+ environment()->Bind(var, value);
+ }
+ }
+ break;
+ case Variable::LOOKUP:
+ return Bailout("unsupported lookup slot in declaration");
}
}
@@ -5874,7 +5917,9 @@ void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
+ new(zone()) HHasInstanceTypeAndBranch(value,
+ JS_FUNCTION_TYPE,
+ JS_FUNCTION_PROXY_TYPE);
return ast_context()->ReturnControl(result, call->id());
}
@@ -6528,6 +6573,8 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
PrintBlockProperty("dominator", current->dominator()->block_id());
}
+ PrintIntProperty("loop_depth", current->LoopNestingDepth());
+
if (chunk != NULL) {
int first_index = current->first_instruction_index();
int last_index = current->last_instruction_index();
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 1066d2cb..03fbc732 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -102,6 +102,7 @@ class HBasicBlock: public ZoneObject {
void RemovePhi(HPhi* phi);
void AddInstruction(HInstruction* instr);
bool Dominates(HBasicBlock* other) const;
+ int LoopNestingDepth() const;
void SetInitialEnvironment(HEnvironment* env);
void ClearEnvironment() { last_environment_ = NULL; }
@@ -242,13 +243,11 @@ class HGraph: public ZoneObject {
// Returns false if there are phi-uses of the arguments-object
// which are not supported by the optimizing compiler.
- bool CheckArgumentsPhiUses();
+ bool CheckPhis();
- // Returns false if there are phi-uses of an uninitialized const
- // which are not supported by the optimizing compiler.
- bool CheckConstPhiUses();
-
- void CollectPhis();
+ // Returns false if there are phi-uses of hole values comming
+ // from uninitialized consts.
+ bool CollectPhis();
Handle<Code> Compile(CompilationInfo* info);
@@ -457,12 +456,11 @@ class HEnvironment: public ZoneObject {
// by 1 (receiver is parameter index -1 but environment index 0).
// Stack-allocated local indices are shifted by the number of parameters.
int IndexFor(Variable* variable) const {
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL && slot->IsStackAllocated());
- int shift = (slot->type() == Slot::PARAMETER)
+ ASSERT(variable->IsStackAllocated());
+ int shift = variable->IsParameter()
? 1
: parameter_count_ + specials_count_;
- return slot->index() + shift;
+ return variable->index() + shift;
}
Handle<JSFunction> closure_;
@@ -781,6 +779,10 @@ class HGraphBuilder: public AstVisitor {
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION
+ void HandleDeclaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* function);
+
void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr);
@@ -853,7 +855,6 @@ class HGraphBuilder: public AstVisitor {
TypeInfo info,
HValue* value,
Representation rep);
- void AssumeRepresentation(HValue* value, Representation rep);
static Representation ToRepresentation(TypeInfo info);
void SetupScope(Scope* scope);
@@ -935,7 +936,7 @@ class HGraphBuilder: public AstVisitor {
HValue* external_elements,
HValue* checked_key,
HValue* val,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
bool is_store);
HInstruction* BuildMonomorphicElementAccess(HValue* object,
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index c186094b..4698e3ed 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -465,6 +465,7 @@ class CpuFeatures : public AllStatic {
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
+
public:
explicit Scope(CpuFeature f) {
uint64_t mask = static_cast<uint64_t>(1) << f;
@@ -484,10 +485,12 @@ class CpuFeatures : public AllStatic {
isolate_->set_enabled_cpu_features(old_enabled_);
}
}
+
private:
Isolate* isolate_;
uint64_t old_enabled_;
#else
+
public:
explicit Scope(CpuFeature f) {}
#endif
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 845a073c..310ea3d1 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -590,16 +590,17 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
- Label non_function;
+ Label slow, non_function;
// 1 ~ return address.
__ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
__ JumpIfSmi(edi, &non_function);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
- __ j(not_equal, &non_function);
+ __ j(not_equal, &slow);
// 3a. Patch the first argument if necessary when calling a function.
Label shift_arguments;
+ __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
@@ -637,6 +638,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(ebx, eax);
+ __ Set(edx, Immediate(0)); // restore
__ pop(eax);
__ SmiUntag(eax);
@@ -661,14 +663,19 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ jmp(&shift_arguments);
}
- // 3b. Patch the first argument when calling a non-function. The
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ Set(edx, Immediate(1)); // indicate function proxy
+ __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
+ __ j(equal, &shift_arguments);
+ __ bind(&non_function);
+ __ Set(edx, Immediate(2)); // indicate non-function
+
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
- __ bind(&non_function);
__ mov(Operand(esp, eax, times_4, 0), edi);
- // Clear edi to indicate a non-function being called.
- __ Set(edi, Immediate(0));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -685,13 +692,26 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ dec(eax); // One fewer argument (first argument is new receiver).
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
- { Label function;
- __ test(edi, Operand(edi));
- __ j(not_zero, &function);
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
+ { Label function, non_proxy;
+ __ test(edx, Operand(edx));
+ __ j(zero, &function);
__ Set(ebx, Immediate(0));
- __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(ecx, CALL_AS_METHOD);
+ __ cmp(Operand(edx), Immediate(1));
+ __ j(not_equal, &non_proxy);
+
+ __ pop(edx); // return address
+ __ push(edi); // re-add proxy object as additional argument
+ __ push(edx);
+ __ inc(eax);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -717,13 +737,17 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+ static const int kArgumentsOffset = 2 * kPointerSize;
+ static const int kReceiverOffset = 3 * kPointerSize;
+ static const int kFunctionOffset = 4 * kPointerSize;
+
__ EnterInternalFrame();
- __ push(Operand(ebp, 4 * kPointerSize)); // push this
- __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
+ __ push(Operand(ebp, kFunctionOffset)); // push this
+ __ push(Operand(ebp, kArgumentsOffset)); // push arguments
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -756,16 +780,21 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(eax); // limit
__ push(Immediate(0)); // index
- // Change context eagerly to get the right global object if
- // necessary.
- __ mov(edi, Operand(ebp, 4 * kPointerSize));
+ // Get the receiver.
+ __ mov(ebx, Operand(ebp, kReceiverOffset));
+
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
+ __ mov(edi, Operand(ebp, kFunctionOffset));
+ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+ __ j(not_equal, &push_receiver);
+
+ // Change context eagerly to get the right global object if necessary.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
- __ mov(ebx, Operand(ebp, 3 * kPointerSize));
-
// Do not transform the receiver for strict mode functions.
+ Label call_to_object, use_global_receiver;
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
@@ -814,7 +843,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ mov(eax, Operand(ebp, kIndexOffset));
__ jmp(&entry);
__ bind(&loop);
- __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
+ __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
// Use inline caching to speed up access to arguments.
Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
@@ -837,14 +866,30 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ j(not_equal, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(eax);
__ SmiUntag(eax);
- __ mov(edi, Operand(ebp, 4 * kPointerSize));
+ __ mov(edi, Operand(ebp, kFunctionOffset));
+ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+ __ j(not_equal, &call_proxy);
__ InvokeFunction(edi, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ LeaveInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(edi); // add function proxy as last argument
+ __ inc(eax);
+ __ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_METHOD);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 85e74b85..1009aaf5 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3551,7 +3551,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
masm->isolate());
__ mov(edx,
Operand::StaticVariable(ExternalReference::the_hole_value_location(
@@ -4199,7 +4199,7 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -4224,7 +4224,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
// Check that the function really is a JavaScript function.
- __ JumpIfSmi(edi, &slow);
+ __ JumpIfSmi(edi, &non_function);
// Goto slow case if we do not have a function.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &slow);
@@ -4251,15 +4251,32 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
+ __ j(not_equal, &non_function);
+ __ pop(ecx);
+ __ push(edi); // put proxy as additional argument under return address
+ __ push(ecx);
+ __ Set(eax, Immediate(argc_ + 1));
+ __ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_FUNCTION);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ jmp(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
__ Set(eax, Immediate(argc_));
__ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_METHOD);
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
- __ SetCallKind(ecx, CALL_AS_METHOD);
__ jmp(adaptor, RelocInfo::CODE_TARGET);
}
@@ -4341,7 +4358,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned);
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, masm->isolate());
+ Isolate::kPendingExceptionAddress, masm->isolate());
// Check that there is no pending exception, otherwise we
// should have returned some failure value.
@@ -4482,11 +4499,11 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ push(ebx);
// Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate());
+ ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
__ push(Operand::StaticVariable(c_entry_fp));
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
masm->isolate());
__ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
__ j(not_equal, &not_outermost_js, Label::kNear);
@@ -4503,7 +4520,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
masm->isolate());
__ mov(Operand::StaticVariable(pending_exception), eax);
__ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
@@ -4554,7 +4571,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Restore the top frame descriptor from the stack.
__ pop(Operand::StaticVariable(ExternalReference(
- Isolate::k_c_entry_fp_address,
+ Isolate::kCEntryFPAddress,
masm->isolate())));
// Restore callee-saved registers (C calling conventions).
@@ -4907,7 +4924,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result_, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
@@ -5178,8 +5196,9 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
__ and_(ecx, Operand(edi));
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ test(ecx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ test(ecx, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii);
__ bind(&ascii_data);
// Allocate an acsii cons string.
@@ -5210,7 +5229,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
- __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime);
+ __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
__ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not
@@ -5236,12 +5255,13 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// ebx: length of resulting flat string as a smi
// edx: second string
Label non_ascii_string_add_flat_result;
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(zero, &non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(zero, &string_add_runtime);
// Both strings are ascii strings. As they are short they are both flat.
@@ -5281,7 +5301,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// edx: second string
__ bind(&non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both
// flat.
@@ -5759,13 +5779,14 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// string's encoding is wrong because we always have to recheck encoding of
// the newly created string's parent anyways due to externalized strings.
Label two_byte_slice, set_slice_header;
- STATIC_ASSERT(kAsciiStringTag != 0);
- __ test(ebx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ test(ebx, Immediate(kStringEncodingMask));
__ j(zero, &two_byte_slice, Label::kNear);
__ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
__ jmp(&set_slice_header, Label::kNear);
__ bind(&two_byte_slice);
- __ AllocateSlicedString(eax, ebx, no_reg, &runtime);
+ __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
__ bind(&set_slice_header);
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
__ SmiTag(ecx);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index df2542e4..ca6ce6e3 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -41,7 +41,6 @@
namespace v8 {
namespace internal {
-
#define __ ACCESS_MASM(masm_)
@@ -192,14 +191,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy parameters into context if necessary.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -241,7 +240,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), eax, ebx, edx);
+ SetVar(arguments, eax, ebx, edx);
}
if (FLAG_trace) {
@@ -255,17 +254,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
@@ -371,27 +372,29 @@ void FullCodeGenerator::verify_stack_height() {
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ mov(result_register(), slot_operand);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ MemOperand operand = codegen()->VarOperand(var, result_register());
// Memory operands can be pushed directly.
- __ push(slot_operand);
+ __ push(operand);
codegen()->increment_stack_height();
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -615,44 +618,54 @@ void FullCodeGenerator::Split(Condition cc,
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return Operand(ebp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return Operand(eax, 0);
+ return Operand(ebp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
- MemOperand location = EmitSlotSearch(source, destination);
- __ mov(destination, location);
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ MemOperand location = VarOperand(var, dest);
+ __ mov(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ mov(location, src);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- int offset = Context::SlotOffset(dst->index());
- ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
- __ RecordWrite(scratch1, offset, src, scratch2);
+ if (var->IsContextSlot()) {
+ int offset = Context::SlotOffset(var->index());
+ ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
+ __ RecordWrite(scratch0, offset, src, scratch1);
}
}
@@ -683,29 +696,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ mov(Operand(ebp, SlotOffset(slot)), result_register());
+ __ mov(StackOperand(variable), result_register());
} else if (mode == Variable::CONST || mode == Variable::LET) {
- __ mov(Operand(ebp, SlotOffset(slot)),
+ Comment cmnt(masm_, "[ Declaration");
+ __ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -718,22 +735,27 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ Check(not_equal, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ mov(ContextOperand(esi, slot->index()), result_register());
- int offset = Context::SlotOffset(slot->index());
+ __ mov(ContextOperand(esi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
__ mov(ebx, esi);
__ RecordWrite(ebx, offset, result_register(), ecx);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
- __ mov(ContextOperand(esi, slot->index()),
+ Comment cmnt(masm_, "[ Declaration");
+ __ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ push(esi);
__ push(Immediate(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -750,7 +772,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ push(Immediate(isolate()->factory()->the_hole_value()));
increment_stack_height();
} else {
- __ push(Immediate(Smi::FromInt(0))); // No initial value!
+ __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
increment_stack_height();
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -761,18 +783,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(esi); // The context is the first argument.
__ push(Immediate(pairs));
- __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags())));
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1071,10 +1090,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register context = esi;
Register temp = edx;
@@ -1123,7 +1141,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global
// load IC call.
__ mov(eax, GlobalObjectOperand());
- __ mov(ecx, slot->var()->name());
+ __ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1132,14 +1150,13 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = esi;
Register temp = ebx;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1159,60 +1176,31 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to
// return an esi-based operand (the write barrier cannot be allowed to
// destroy the esi register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ mov(eax,
- ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, done);
- __ mov(eax, isolate()->factory()->undefined_value());
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ mov(edx,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ SafeSet(eax, Immediate(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ cmp(eax, isolate()->factory()->the_hole_value());
+ __ j(not_equal, done);
+ __ mov(eax, isolate()->factory()->undefined_value());
}
+ __ jmp(done);
}
}
@@ -1222,66 +1210,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in ecx and the global
- // object on the stack.
- __ mov(eax, GlobalObjectOperand());
- __ mov(ecx, var->name());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(eax);
-
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in ecx and the global
+ // object in eax.
+ __ mov(eax, GlobalObjectOperand());
+ __ mov(ecx, var->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(eax);
+ break;
+ }
- context()->Plug(eax);
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ Label done;
+ GetVar(eax, var);
+ __ cmp(eax, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &done, Label::kNear);
+ if (var->mode() == Variable::LET) {
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ } else { // Variable::CONST
+ __ mov(eax, isolate()->factory()->undefined_value());
+ }
+ __ bind(&done);
+ context()->Plug(eax);
+ }
+ break;
+ }
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, eax);
- __ mov(eax, slot_operand);
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, &done, Label::kNear);
- __ mov(eax, isolate()->factory()->undefined_value());
- __ bind(&done);
- context()->Plug(eax);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, eax);
- __ mov(eax, slot_operand);
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, &done, Label::kNear);
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ push(esi); // Context.
__ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(eax);
- } else {
- context()->Plug(slot);
+ break;
}
}
}
@@ -1824,14 +1806,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in eax, variable name in
- // ecx, and the global object on the stack.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
@@ -1840,117 +1816,79 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- __ mov(edx, Operand(ebp, SlotOffset(slot)));
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &skip);
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(eax);
- __ push(esi);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ mov(edx, StackOperand(var));
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &skip);
+ __ mov(StackOperand(var), eax);
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(eax);
+ __ push(esi);
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ mov(edx, Operand(ebp, SlotOffset(slot)));
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &assign);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
- }
-
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, ecx);
- // Check for an initialized let binding.
- __ mov(edx, target);
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &assign, Label::kNear);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ mov(target, eax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(eax); // Value.
+ __ push(esi); // Context.
+ __ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, ecx);
+ __ mov(edx, location);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &assign, Label::kNear);
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ __ mov(location, eax);
+ if (var->IsContextSlot()) {
__ mov(edx, eax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(ecx, offset, edx, ebx);
- break;
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(eax); // Value.
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
- } else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, ecx);
- // Perform the assignment and issue the write barrier.
- __ mov(target, eax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
+ } else if (var->mode() != Variable::CONST) {
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, ecx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ mov(edx, location);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ Check(equal, "Let binding re-initialization.");
+ }
+ // Perform the assignment.
+ __ mov(location, eax);
+ if (var->IsContextSlot()) {
__ mov(edx, eax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(ecx, offset, edx, ebx);
- break;
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(eax); // Value.
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(eax); // Value.
+ __ push(esi); // Context.
+ __ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2075,9 +2013,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2109,9 +2046,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
- arg_count, in_loop);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2133,8 +2069,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2157,8 +2092,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
// Push the receiver of the enclosing function.
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
- // Push the strict mode flag.
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ push(Immediate(Smi::FromInt(strict_mode)));
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
? Runtime::kResolvePossiblyDirectEvalNoLookup
@@ -2174,18 +2114,18 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
- // resolve the function we need to call and the receiver of the
- // call. Then we call the resolved function using the given
- // arguments.
+ // resolve the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
// Reserved receiver slot.
__ push(Immediate(isolate()->factory()->undefined_value()));
increment_stack_height();
@@ -2195,15 +2135,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// If we know that eval can only be shadowed by eval-introduced
- // variables we attempt to load the global eval function directly
- // in generated code. If we succeed, there is no need to perform a
+ // variables we attempt to load the global eval function directly in
+ // generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(eax);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2211,13 +2150,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
@@ -2226,83 +2163,74 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
decrement_stack_height(arg_count + 1); // Function is left on the stack.
context()->DropAndPlug(1, eax);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ push(GlobalObjectOperand());
increment_stack_height();
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
-
{ PreservePositionScope scope(masm()->positions_recorder());
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ // Generate code for loading from variables potentially shadowed by
+ // eval-introduced variables.
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
-
__ bind(&slow);
- // Call the runtime to find the function to call (returned in eax)
- // and the object holding it (returned in edx).
+ // Call the runtime to find the function to call (returned in eax) and
+ // the object holding it (returned in edx).
__ push(context_register());
- __ push(Immediate(var->name()));
+ __ push(Immediate(proxy->name()));
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(eax); // Function.
- increment_stack_height();
__ push(edx); // Receiver.
- increment_stack_height();
+ increment_stack_height(2);
- // If fast case code has been generated, emit code to push the
- // function and receiver and have the slow path jump around this
- // code.
+ // If fast case code has been generated, emit code to push the function
+ // and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
- __ jmp(&call);
+ __ jmp(&call, Label::kNear);
__ bind(&done);
- // Push function. Stack height already incremented in slow case above.
+ // Push function. Stack height already incremented in slow case
+ // above.
__ push(eax);
- // The receiver is implicitly the global receiver. Indicate this
- // by passing the hole to the call function stub.
+ // The receiver is implicitly the global receiver. Indicate this by
+ // passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->the_hole_value()));
__ bind(&call);
}
- // The receiver is either the global receiver or an object found
- // by LoadContextSlot. That object could be the hole if the
- // receiver is implicitly the global object.
+ // The receiver is either the global receiver or an object found by
+ // LoadContextSlot. That object could be the hole if the receiver is
+ // implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
+
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ mov(ebx, GlobalObjectOperand());
@@ -3650,10 +3578,9 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Call the JS runtime function via a call IC.
__ Set(ecx, Immediate(expr->name()));
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
- Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
- arg_count, in_loop, mode);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -3674,31 +3601,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
decrement_stack_height(2);
context()->Plug(eax);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(kNonStrictMode)));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(eax);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- context()->Plug(false);
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is
+ // not really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3995,7 +3923,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name()));
@@ -4005,15 +3933,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(eax);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ push(esi);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 7d3ead2e..9b5cc564 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -144,7 +144,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
@@ -198,9 +198,9 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(kTypeAndReadOnlyMask));
__ j(not_zero, miss_label);
@@ -832,7 +832,6 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1237,9 +1236,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
edx);
@@ -1339,10 +1336,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
// -- esp[0] : return address
// -----------------------------------
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
no_reg);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 32e3074d..4e3ea981 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -88,7 +88,8 @@ void LCodeGen::FinishCode(Handle<Code> code) {
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -194,14 +195,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have to use a third register to avoid
@@ -2219,11 +2220,11 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Map::kElementsKindMask);
__ shr(temp, Map::kElementsKindShift);
- __ cmp(temp, JSObject::FAST_ELEMENTS);
+ __ cmp(temp, FAST_ELEMENTS);
__ j(equal, &ok, Label::kNear);
- __ cmp(temp, JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less, &fail, Label::kNear);
- __ cmp(temp, JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
@@ -2264,7 +2265,7 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ mov(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
- JSObject::FAST_ELEMENTS,
+ FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
@@ -2284,14 +2285,14 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
- JSObject::FAST_DOUBLE_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
offset);
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(result, double_load_operand);
}
@@ -2300,7 +2301,7 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
@@ -2320,35 +2321,35 @@ Operand LCodeGen::BuildFastArrayOperand(
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movdbl(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsx_b(result, operand);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movzx_b(result, operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzx_w(result, operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ mov(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(result, operand);
__ test(result, Operand(result));
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2356,12 +2357,12 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(negative, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -2980,8 +2981,8 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = isolate()->stub_cache()->
- ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2993,7 +2994,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(ecx, instr->name());
CallCode(ic, mode, instr);
}
@@ -3004,7 +3005,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ Drop(1);
}
@@ -3017,7 +3018,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(ecx, instr->name());
CallCode(ic, mode, instr);
}
@@ -3103,36 +3104,36 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movdbl(operand, ToDoubleRegister(instr->value()));
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ mov_b(operand, value);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(operand, value);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(operand, value);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3175,7 +3176,6 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
- Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
Label have_value;
__ ucomisd(value, value);
@@ -3187,7 +3187,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(double_store_operand, value);
}
@@ -3269,7 +3269,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index d26f2455..61563274 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -224,7 +224,7 @@ class LCodeGen BASE_EMBEDDED {
int ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index f59ee07d..3dc220d3 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -315,13 +315,13 @@ void LCallKeyed::PrintDataTo(StringStream* stream) {
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -540,7 +540,8 @@ LChunk* LChunkBuilder::Build() {
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -706,9 +707,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -995,13 +994,10 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1011,6 +1007,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1019,7 +1016,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1906,15 +1903,15 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1924,7 +1921,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS)
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS)
? AssignEnvironment(load_instr)
: load_instr;
}
@@ -1976,23 +1973,23 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* val = NULL;
- if (elements_kind == JSObject::EXTERNAL_BYTE_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// We need a byte register in this case for the value.
val = UseFixed(instr->value(), eax);
} else {
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 4b407a32..038049ca 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1184,7 +1184,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1699,7 +1699,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2259,8 +2259,7 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index dff174cb..837112a5 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -287,7 +287,7 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Map::kMaximumBitField2FastElementValue);
j(above, fail, distance);
@@ -437,9 +437,9 @@ void MacroAssembler::EnterExitFramePrologue() {
push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
- ExternalReference context_address(Isolate::k_context_address,
+ ExternalReference context_address(Isolate::kContextAddress,
isolate());
mov(Operand::StaticVariable(c_entry_fp_address), ebp);
mov(Operand::StaticVariable(context_address), esi);
@@ -518,14 +518,14 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Isolate::k_context_address, isolate());
+ ExternalReference context_address(Isolate::kContextAddress, isolate());
mov(esi, Operand::StaticVariable(context_address));
#ifdef DEBUG
mov(Operand::StaticVariable(context_address), Immediate(0));
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
}
@@ -567,10 +567,10 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(Smi::FromInt(0))); // No context.
}
// Save the current handler as the next handler.
- push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ push(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())));
// Link this handler as the new current one.
- mov(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ mov(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())),
esp);
}
@@ -578,7 +578,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ pop(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())));
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
}
@@ -598,7 +598,7 @@ void MacroAssembler::Throw(Register value) {
}
// Drop the sp to the top of the handler.
- ExternalReference handler_address(Isolate::k_handler_address,
+ ExternalReference handler_address(Isolate::kHandlerAddress,
isolate());
mov(esp, Operand::StaticVariable(handler_address));
@@ -637,7 +637,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
}
// Drop sp to the top stack handler.
- ExternalReference handler_address(Isolate::k_handler_address,
+ ExternalReference handler_address(Isolate::kHandlerAddress,
isolate());
mov(esp, Operand::StaticVariable(handler_address));
@@ -660,13 +660,13 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address,
+ Isolate::kExternalCaughtExceptionAddress,
isolate());
mov(eax, false);
mov(Operand::StaticVariable(external_caught), eax);
// Set pending exception and eax to out of memory exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate());
mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
mov(Operand::StaticVariable(pending_exception), eax);
@@ -840,7 +840,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
- Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
j(not_zero, miss);
// Get the value at the masked, scaled index.
@@ -1172,7 +1172,7 @@ void MacroAssembler::AllocateAsciiString(Register result,
}
-void MacroAssembler::AllocateConsString(Register result,
+void MacroAssembler::AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
@@ -1208,7 +1208,7 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
}
-void MacroAssembler::AllocateSlicedString(Register result,
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index de9361da..1906644c 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -437,7 +437,7 @@ class MacroAssembler: public Assembler {
// Allocate a raw cons string object. Only the map field of the result is
// initialized.
- void AllocateConsString(Register result,
+ void AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
@@ -448,7 +448,7 @@ class MacroAssembler: public Assembler {
// Allocate a raw sliced string object. Only the map field of the result is
// initialized.
- void AllocateSlicedString(Register result,
+ void AllocateTwoByteSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 621a9bbf..ab62764e 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -2679,7 +2679,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
// -- esp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_jsarray, elements_kind).TryGetCode();
@@ -3140,7 +3140,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
// -- esp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(edx,
@@ -3385,7 +3385,7 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3407,29 +3407,29 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ SmiUntag(eax); // Untag the index.
__ movsx_b(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ SmiUntag(eax); // Untag the index.
__ movzx_b(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzx_w(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ mov(ecx, Operand(ebx, eax, times_2, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ fld_s(Operand(ebx, eax, times_2, 0));
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ fld_d(Operand(ebx, eax, times_4, 0));
break;
default:
@@ -3442,17 +3442,17 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// For floating-point array type:
// FP(0): value
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
Label box_int;
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
__ cmp(ecx, 0xC0000000);
__ j(sign, &box_int);
} else {
- ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
+ ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3468,12 +3468,12 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Allocate a HeapNumber for the int and perform int-to-double
// conversion.
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
__ push(ecx);
__ fild_s(Operand(esp, 0));
__ pop(ecx);
} else {
- ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
+ ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// Need to zero-extend the value.
// There's no fild variant for unsigned values, so zero-extend
// to a 64-bit int manually.
@@ -3489,8 +3489,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ mov(eax, ecx);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
@@ -3540,7 +3540,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3566,7 +3566,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver
// ecx: key
// edi: elements array
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
__ JumpIfNotSmi(eax, &slow);
} else {
__ JumpIfNotSmi(eax, &check_heap_number);
@@ -3578,33 +3578,33 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// edi: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(ebx);
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(Operand(edi, ecx, times_2, 0), ebx);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ push(ebx);
__ fild_s(Operand(esp, 0));
__ pop(ebx);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ fstp_s(Operand(edi, ecx, times_2, 0));
- } else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
+ } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
__ fstp_d(Operand(edi, ecx, times_4, 0));
}
break;
@@ -3615,7 +3615,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ret(0); // Return the original value.
// TODO(danno): handle heap number -> pixel array conversion
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
__ bind(&check_heap_number);
// eax: value
// edx: receiver
@@ -3630,11 +3630,11 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// reproducible behavior, convert these to zero.
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// edi: base pointer of external storage
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_s(Operand(edi, ecx, times_2, 0));
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_d(Operand(edi, ecx, times_4, 0));
__ ret(0);
@@ -3647,23 +3647,23 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// (code-stubs-ia32.cc) is roughly what is needed here though the
// conversion failure case does not need to be handled.
if (CpuFeatures::IsSupported(SSE2)) {
- if (elements_kind != JSObject::EXTERNAL_INT_ELEMENTS &&
- elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind != EXTERNAL_INT_ELEMENTS &&
+ elements_kind != EXTERNAL_UNSIGNED_INT_ELEMENTS) {
ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
// ecx: untagged integer value
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(ebx);
// Fall through.
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
default:
diff --git a/src/ic.cc b/src/ic.cc
index 0d0b9357..0f76a9a0 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -61,8 +61,7 @@ static char TransitionMarkFromState(IC::State state) {
void IC::TraceIC(const char* type,
Handle<Object> name,
State old_state,
- Code* new_target,
- const char* extra_info) {
+ Code* new_target) {
if (FLAG_trace_ic) {
State new_state = StateFrom(new_target,
HEAP->undefined_value(),
@@ -94,10 +93,9 @@ void IC::TraceIC(const char* type,
} else {
PrintF("<unknown>");
}
- PrintF(" (%c->%c)%s",
+ PrintF(" (%c->%c)",
TransitionMarkFromState(old_state),
- TransitionMarkFromState(new_state),
- extra_info);
+ TransitionMarkFromState(new_state));
name->Print();
PrintF("]\n");
}
@@ -326,7 +324,6 @@ void CallICBase::Clear(Address address, Code* target) {
Code* code =
Isolate::Current()->stub_cache()->FindCallInitialize(
target->arguments_count(),
- target->ic_in_loop(),
contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
target->kind());
SetTargetAtAddress(address, code);
@@ -604,13 +601,11 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
Handle<Object> object,
Handle<String> name) {
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -626,7 +621,6 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
JSFunction* function = lookup->GetConstantFunction();
maybe_code =
isolate()->stub_cache()->ComputeCallConstant(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -646,7 +640,6 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
if (!cell->value()->IsJSFunction()) return NULL;
JSFunction* function = JSFunction::cast(cell->value());
maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -661,7 +654,6 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
// applicable.
if (lookup->holder() != *receiver) return NULL;
maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -706,7 +698,6 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
// Compute the number of arguments.
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
bool had_proto_failure = false;
if (state == UNINITIALIZED) {
@@ -715,7 +706,6 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
// setting the monomorphic state.
maybe_code =
isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
- in_loop,
kind_,
extra_ic_state);
} else if (state == MONOMORPHIC) {
@@ -739,7 +729,6 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
} else {
maybe_code =
isolate()->stub_cache()->ComputeCallMegamorphic(argc,
- in_loop,
kind_,
extra_ic_state);
}
@@ -776,7 +765,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
#ifdef DEBUG
if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
- name, state, target(), in_loop ? " (in-loop)" : "");
+ name, state, target());
#endif
}
@@ -797,31 +786,28 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
Map* map = heap->non_strict_arguments_elements_map();
if (object->IsJSObject() &&
Handle<JSObject>::cast(object)->elements()->map() == map) {
MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
- argc, in_loop, Code::KEYED_CALL_IC);
+ argc, Code::KEYED_CALL_IC);
Object* code;
if (maybe_code->ToObject(&code)) {
set_target(Code::cast(code));
#ifdef DEBUG
- TraceIC(
- "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
+ TraceIC("KeyedCallIC", key, state, target());
#endif
}
} else if (FLAG_use_ic && state != MEGAMORPHIC &&
!object->IsAccessCheckNeeded()) {
MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
- argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
+ argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
Object* code;
if (maybe_code->ToObject(&code)) {
set_target(Code::cast(code));
#ifdef DEBUG
- TraceIC(
- "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
+ TraceIC("KeyedCallIC", key, state, target());
#endif
}
}
@@ -1093,7 +1079,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
return KeyedLoadElementStub(elements_kind).TryGetCode();
}
@@ -1650,7 +1636,6 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
Code::Flags flags = Code::ComputeFlags(this->kind(),
- NOT_IN_LOOP,
MEGAMORPHIC,
strict_mode);
Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
@@ -1721,7 +1706,7 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
}
@@ -1905,16 +1890,11 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
//
static JSFunction* CompileFunction(Isolate* isolate,
- JSFunction* function,
- InLoopFlag in_loop) {
+ JSFunction* function) {
// Compile now with optimization.
HandleScope scope(isolate);
Handle<JSFunction> function_handle(function, isolate);
- if (in_loop == IN_LOOP) {
- CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
- } else {
- CompileLazy(function_handle, CLEAR_EXCEPTION);
- }
+ CompileLazy(function_handle, CLEAR_EXCEPTION);
return *function_handle;
}
@@ -1943,9 +1923,7 @@ RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(isolate,
- JSFunction::cast(result),
- ic.target()->ic_in_loop());
+ return CompileFunction(isolate, JSFunction::cast(result));
}
@@ -1964,9 +1942,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(isolate,
- JSFunction::cast(result),
- ic.target()->ic_in_loop());
+ return CompileFunction(isolate, JSFunction::cast(result));
}
diff --git a/src/ic.h b/src/ic.h
index 2236ba37..ece5be9f 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -149,8 +149,7 @@ class IC {
void TraceIC(const char* type,
Handle<Object> name,
State old_state,
- Code* new_target,
- const char* extra_info = "");
+ Code* new_target);
#endif
Failure* TypeError(const char* type,
@@ -348,7 +347,7 @@ class KeyedIC: public IC {
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) = 0;
+ ElementsKind elements_kind) = 0;
protected:
virtual Code* string_stub() {
@@ -415,7 +414,7 @@ class KeyedLoadIC: public KeyedIC {
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
@@ -566,7 +565,7 @@ class KeyedStoreIC: public KeyedIC {
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
diff --git a/src/inspector.h b/src/inspector.h
index f8b30428..e328bcdf 100644
--- a/src/inspector.h
+++ b/src/inspector.h
@@ -41,7 +41,6 @@ namespace internal {
class Inspector {
public:
-
static void DumpObjectType(FILE* out, Object *obj, bool print_more);
static void DumpObjectType(FILE* out, Object *obj) {
DumpObjectType(out, obj, false);
@@ -59,4 +58,3 @@ class Inspector {
#endif // INSPECTOR
#endif // V8_INSPECTOR_H_
-
diff --git a/src/isolate.cc b/src/isolate.cc
index 09cbc8a1..fd0f673e 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -43,7 +43,6 @@
#include "messages.h"
#include "regexp-stack.h"
#include "runtime-profiler.h"
-#include "scanner.h"
#include "scopeinfo.h"
#include "serialize.h"
#include "simulator.h"
@@ -1409,14 +1408,13 @@ Isolate::Isolate()
global_handles_(NULL),
context_switcher_(NULL),
thread_manager_(NULL),
- ast_sentinels_(NULL),
string_tracker_(NULL),
regexp_stack_(NULL),
embedder_data_(NULL) {
TRACE_ISOLATE(constructor);
memset(isolate_addresses_, 0,
- sizeof(isolate_addresses_[0]) * (k_isolate_address_count + 1));
+ sizeof(isolate_addresses_[0]) * (kIsolateAddressCount + 1));
heap_.isolate_ = this;
zone_.isolate_ = this;
@@ -1546,9 +1544,6 @@ Isolate::~Isolate() {
delete regexp_stack_;
regexp_stack_ = NULL;
- delete ast_sentinels_;
- ast_sentinels_ = NULL;
-
delete descriptor_lookup_cache_;
descriptor_lookup_cache_ = NULL;
delete context_slot_cache_;
@@ -1691,9 +1686,10 @@ bool Isolate::Init(Deserializer* des) {
// ensuring that Isolate::Current() == this.
heap_.SetStackLimits();
-#define C(name) isolate_addresses_[Isolate::k_##name] = \
- reinterpret_cast<Address>(name());
- ISOLATE_ADDRESS_LIST(C)
+#define ASSIGN_ELEMENT(CamelName, hacker_name) \
+ isolate_addresses_[Isolate::k##CamelName##Address] = \
+ reinterpret_cast<Address>(hacker_name##_address());
+ FOR_EACH_ISOLATE_ADDRESS_NAME(ASSIGN_ELEMENT)
#undef C
string_tracker_ = new StringTracker();
@@ -1710,7 +1706,6 @@ bool Isolate::Init(Deserializer* des) {
bootstrapper_ = new Bootstrapper();
handle_scope_implementer_ = new HandleScopeImplementer(this);
stub_cache_ = new StubCache(this);
- ast_sentinels_ = new AstSentinels();
regexp_stack_ = new RegExpStack();
regexp_stack_->isolate_ = this;
diff --git a/src/isolate.h b/src/isolate.h
index 5bb504d2..2582da64 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -47,7 +47,6 @@
namespace v8 {
namespace internal {
-class AstSentinels;
class Bootstrapper;
class CodeGenerator;
class CodeRange;
@@ -120,13 +119,13 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
#define RETURN_IF_EMPTY_HANDLE(isolate, call) \
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, Failure::Exception())
-#define ISOLATE_ADDRESS_LIST(C) \
- C(handler_address) \
- C(c_entry_fp_address) \
- C(context_address) \
- C(pending_exception_address) \
- C(external_caught_exception_address) \
- C(js_entry_sp_address)
+#define FOR_EACH_ISOLATE_ADDRESS_NAME(C) \
+ C(Handler, handler) \
+ C(CEntryFP, c_entry_fp) \
+ C(Context, context) \
+ C(PendingException, pending_exception) \
+ C(ExternalCaughtException, external_caught_exception) \
+ C(JSEntrySP, js_entry_sp)
// Platform-independent, reliable thread identifier.
@@ -424,10 +423,10 @@ class Isolate {
enum AddressId {
-#define C(name) k_##name,
- ISOLATE_ADDRESS_LIST(C)
+#define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address,
+ FOR_EACH_ISOLATE_ADDRESS_NAME(DECLARE_ENUM)
#undef C
- k_isolate_address_count
+ kIsolateAddressCount
};
// Returns the PerIsolateThreadData for the current thread (or NULL if one is
@@ -878,8 +877,6 @@ class Isolate {
return &objects_string_input_buffer_;
}
- AstSentinels* ast_sentinels() { return ast_sentinels_; }
-
RuntimeState* runtime_state() { return &runtime_state_; }
StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() {
@@ -1100,7 +1097,7 @@ class Isolate {
StringStream* incomplete_message_;
// The preallocated memory thread singleton.
PreallocatedMemoryThread* preallocated_memory_thread_;
- Address isolate_addresses_[k_isolate_address_count + 1]; // NOLINT
+ Address isolate_addresses_[kIsolateAddressCount + 1]; // NOLINT
NoAllocationStringAllocator* preallocated_message_space_;
Bootstrapper* bootstrapper_;
@@ -1138,7 +1135,6 @@ class Isolate {
GlobalHandles* global_handles_;
ContextSwitcher* context_switcher_;
ThreadManager* thread_manager_;
- AstSentinels* ast_sentinels_;
RuntimeState runtime_state_;
StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_;
Builtins builtins_;
diff --git a/src/json.js b/src/json.js
index 8fd410fa..deba1262 100644
--- a/src/json.js
+++ b/src/json.js
@@ -54,7 +54,7 @@ function Revive(holder, name, reviver) {
function JSONParse(text, reviver) {
var unfiltered = %ParseJson(TO_STRING_INLINE(text));
- if (IS_FUNCTION(reviver)) {
+ if (IS_SPEC_FUNCTION(reviver)) {
return Revive({'': unfiltered}, '', reviver);
} else {
return unfiltered;
@@ -143,11 +143,11 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) {
var value = holder[key];
if (IS_SPEC_OBJECT(value)) {
var toJSON = value.toJSON;
- if (IS_FUNCTION(toJSON)) {
+ if (IS_SPEC_FUNCTION(toJSON)) {
value = %_CallFunction(value, key, toJSON);
}
}
- if (IS_FUNCTION(replacer)) {
+ if (IS_SPEC_FUNCTION(replacer)) {
value = %_CallFunction(holder, key, value, replacer);
}
if (IS_STRING(value)) {
@@ -273,7 +273,7 @@ function BasicSerializeObject(value, stack, builder) {
function BasicJSONSerialize(key, value, stack, builder) {
if (IS_SPEC_OBJECT(value)) {
var toJSON = value.toJSON;
- if (IS_FUNCTION(toJSON)) {
+ if (IS_SPEC_FUNCTION(toJSON)) {
value = %_CallFunction(value, ToString(key), toJSON);
}
}
@@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) {
return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
}
-function SetupJSON() {
+function SetUpJSON() {
+ %CheckIsBootstrapping();
InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse,
"stringify", JSONStringify
));
}
-SetupJSON();
+SetUpJSON()
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 4ca83a47..3ebfbdfc 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -2661,7 +2661,8 @@ int TextNode::GreedyLoopTextLength() {
// this alternative and back to this choice node. If there are variable
// length nodes or other complications in the way then return a sentinel
// value indicating that a greedy loop cannot be constructed.
-int ChoiceNode::GreedyLoopTextLength(GuardedAlternative* alternative) {
+int ChoiceNode::GreedyLoopTextLengthForAlternative(
+ GuardedAlternative* alternative) {
int length = 0;
RegExpNode* node = alternative->node();
// Later we will generate code for all these text nodes using recursion
@@ -2700,7 +2701,8 @@ void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) {
void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
if (trace->stop_node() == this) {
- int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+ int text_length =
+ GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
// Update the counter-based backtracking info on the stack. This is an
// optimization for greedy loops (see below).
@@ -2893,7 +2895,7 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
Trace* current_trace = trace;
- int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+ int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
bool greedy_loop = false;
Label greedy_loop_label;
Trace counter_backtrack_trace;
diff --git a/src/jsregexp.h b/src/jsregexp.h
index 13f9e2ea..54297a49 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -255,6 +255,7 @@ class SetRelation BASE_EMBEDDED {
return (bits_ == (kInFirst | kInSecond | kInBoth));
}
int value() { return bits_; }
+
private:
int bits_;
};
@@ -404,6 +405,7 @@ class DispatchTable : public ZoneObject {
template <typename Callback>
void ForEach(Callback* callback) { return tree()->ForEach(callback); }
+
private:
// There can't be a static empty set since it allocates its
// successors in a zone and caches them.
@@ -793,6 +795,7 @@ class ActionNode: public SeqRegExpNode {
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
virtual ActionNode* Clone() { return new ActionNode(*this); }
virtual int ComputeFirstCharacterSet(int budget);
+
private:
union {
struct {
@@ -861,6 +864,7 @@ class TextNode: public SeqRegExpNode {
}
void CalculateOffsets();
virtual int ComputeFirstCharacterSet(int budget);
+
private:
enum TextEmitPassType {
NON_ASCII_MATCH, // Check for characters that can't match.
@@ -925,6 +929,7 @@ class AssertionNode: public SeqRegExpNode {
virtual AssertionNode* Clone() { return new AssertionNode(*this); }
AssertionNodeType type() { return type_; }
void set_type(AssertionNodeType type) { type_ = type; }
+
private:
AssertionNode(AssertionNodeType t, RegExpNode* on_success)
: SeqRegExpNode(on_success), type_(t) { }
@@ -955,6 +960,7 @@ class BackReferenceNode: public SeqRegExpNode {
}
virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
virtual int ComputeFirstCharacterSet(int budget);
+
private:
int start_reg_;
int end_reg_;
@@ -1071,7 +1077,7 @@ class ChoiceNode: public RegExpNode {
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
protected:
- int GreedyLoopTextLength(GuardedAlternative* alternative);
+ int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
ZoneList<GuardedAlternative>* alternatives_;
private:
@@ -1301,6 +1307,7 @@ class Trace {
}
void InvalidateCurrentCharacter();
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
+
private:
int FindAffectedRegisters(OutSet* affected_registers);
void PerformDeferredActions(RegExpMacroAssembler* macro,
@@ -1402,6 +1409,7 @@ FOR_EACH_NODE_TYPE(DECLARE_VISIT)
void fail(const char* error_message) {
error_message_ = error_message;
}
+
private:
bool ignore_case_;
bool is_ascii_;
diff --git a/src/list-inl.h b/src/list-inl.h
index 8ef7514f..80bccc9b 100644
--- a/src/list-inl.h
+++ b/src/list-inl.h
@@ -207,6 +207,35 @@ void List<T, P>::Initialize(int capacity) {
}
+template <typename T>
+int SortedListBSearch(
+ const List<T>& list, T elem, int (*cmp)(const T* x, const T* y)) {
+ int low = 0;
+ int high = list.length() - 1;
+ while (low <= high) {
+ int mid = (low + high) / 2;
+ T mid_elem = list[mid];
+
+ if (mid_elem > elem) {
+ high = mid - 1;
+ continue;
+ }
+ if (mid_elem < elem) {
+ low = mid + 1;
+ continue;
+ }
+ // Found the elememt.
+ return mid;
+ }
+ return -1;
+}
+
+
+template <typename T>
+int SortedListBSearch(const List<T>& list, T elem) {
+ return SortedListBSearch<T>(list, elem, PointerValueCompare<T>);
+}
+
} } // namespace v8::internal
#endif // V8_LIST_INL_H_
diff --git a/src/list.h b/src/list.h
index ca2b7bce..05587090 100644
--- a/src/list.h
+++ b/src/list.h
@@ -49,7 +49,6 @@ namespace internal {
template <typename T, class P>
class List {
public:
-
List() { Initialize(0); }
INLINE(explicit List(int capacity)) { Initialize(capacity); }
INLINE(~List()) { DeleteData(data_); }
@@ -169,6 +168,15 @@ class Code;
typedef List<Map*> MapList;
typedef List<Code*> CodeList;
+// Perform binary search for an element in an already sorted
+// list. Returns the index of the element of -1 if it was not found.
+template <typename T>
+int SortedListBSearch(
+ const List<T>& list, T elem, int (*cmp)(const T* x, const T* y));
+template <typename T>
+int SortedListBSearch(const List<T>& list, T elem);
+
} } // namespace v8::internal
+
#endif // V8_LIST_H_
diff --git a/src/lithium.cc b/src/lithium.cc
index 64ef469b..5410f6f0 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -166,25 +166,25 @@ void LPointerMap::PrintTo(StringStream* stream) {
}
-int ElementsKindToShiftSize(JSObject::ElementsKind elements_kind) {
+int ElementsKindToShiftSize(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
return 0;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
return 1;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
return 2;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
return 3;
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
return kPointerSizeLog2;
}
UNREACHABLE();
diff --git a/src/lithium.h b/src/lithium.h
index 6010b777..20da21a6 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -165,8 +165,7 @@ class LUnallocated: public LOperand {
}
Policy policy() const { return PolicyField::decode(value_); }
void set_policy(Policy policy) {
- value_ &= ~PolicyField::mask();
- value_ |= PolicyField::encode(policy);
+ value_ = PolicyField::update(value_, policy);
}
int fixed_index() const {
return static_cast<int>(value_) >> kFixedIndexShift;
@@ -177,8 +176,7 @@ class LUnallocated: public LOperand {
}
void set_virtual_register(unsigned id) {
- value_ &= ~VirtualRegisterField::mask();
- value_ |= VirtualRegisterField::encode(id);
+ value_ = VirtualRegisterField::update(value_, id);
}
LUnallocated* CopyUnconstrained() {
@@ -586,7 +584,7 @@ class DeepIterator BASE_EMBEDDED {
};
-int ElementsKindToShiftSize(JSObject::ElementsKind elements_kind);
+int ElementsKindToShiftSize(ElementsKind elements_kind);
} } // namespace v8::internal
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 0b01e8af..d44c2fc1 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -860,8 +860,7 @@ class FunctionInfoListener {
int j = 0;
for (int i = 0; i < list.length(); i++) {
Variable* var1 = list[i];
- Slot* slot = var1->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ if (var1->IsContextSlot()) {
if (j != i) {
list[j] = var1;
}
@@ -873,7 +872,7 @@ class FunctionInfoListener {
for (int k = 1; k < j; k++) {
int l = k;
for (int m = k + 1; m < j; m++) {
- if (list[l]->AsSlot()->index() > list[m]->AsSlot()->index()) {
+ if (list[l]->index() > list[m]->index()) {
l = m;
}
}
@@ -887,7 +886,7 @@ class FunctionInfoListener {
SetElementNonStrict(
scope_info_list,
scope_info_length,
- Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())));
+ Handle<Smi>(Smi::FromInt(list[i]->index())));
scope_info_length++;
}
SetElementNonStrict(scope_info_list,
@@ -1451,7 +1450,7 @@ static bool FixTryCatchHandler(StackFrame* top_frame,
StackFrame* bottom_frame) {
Address* pointer_address =
&Memory::Address_at(Isolate::Current()->get_address_from_id(
- Isolate::k_handler_address));
+ Isolate::kHandlerAddress));
while (*pointer_address < top_frame->sp()) {
pointer_address = &Memory::Address_at(*pointer_address);
diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc
index 451a28ab..957c0515 100644
--- a/src/liveobjectlist.cc
+++ b/src/liveobjectlist.cc
@@ -184,7 +184,7 @@ bool IsOfType(LiveObjectType type, HeapObject *obj) {
const AllocationSpace kInvalidSpace = static_cast<AllocationSpace>(-1);
static AllocationSpace FindSpaceFor(String* space_str) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
space_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
const char* key_str = *s;
@@ -236,7 +236,7 @@ static bool InSpace(AllocationSpace space, HeapObject *heap_obj) {
static LiveObjectType FindTypeFor(String* type_str) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
type_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
#define CHECK_OBJECT_TYPE(type_, name) { \
@@ -503,10 +503,10 @@ static void GenerateObjectDesc(HeapObject* obj,
// We'll only dump 80 of them after we compact them.
const int kMaxCharToDump = 80;
const int kMaxBufferSize = kMaxCharToDump * 2;
- SmartPointer<char> str_sp = str->ToCString(DISALLOW_NULLS,
- ROBUST_STRING_TRAVERSAL,
- 0,
- kMaxBufferSize);
+ SmartArrayPointer<char> str_sp = str->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL,
+ 0,
+ kMaxBufferSize);
char* str_cstr = *str_sp;
int length = CompactString(str_cstr);
OS::SNPrintF(buffer_v,
@@ -526,14 +526,14 @@ static void GenerateObjectDesc(HeapObject* obj,
}
String* name = sinfo->DebugName();
- SmartPointer<char> name_sp =
+ SmartArrayPointer<char> name_sp =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
char* name_cstr = *name_sp;
HeapStringAllocator string_allocator;
StringStream stream(&string_allocator);
sinfo->SourceCodePrint(&stream, 50);
- SmartPointer<const char> source_sp = stream.ToCString();
+ SmartArrayPointer<const char> source_sp = stream.ToCString();
const char* source_cstr = *source_sp;
OS::SNPrintF(buffer_v,
@@ -1656,7 +1656,7 @@ int LiveObjectList::GetObjId(Object* obj) {
// Gets the obj id for the specified address if valid.
Object* LiveObjectList::GetObjId(Handle<String> address) {
- SmartPointer<char> addr_str =
+ SmartArrayPointer<char> addr_str =
address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Isolate* isolate = Isolate::Current();
diff --git a/src/liveobjectlist.h b/src/liveobjectlist.h
index 542482d9..65470d7a 100644
--- a/src/liveobjectlist.h
+++ b/src/liveobjectlist.h
@@ -114,7 +114,6 @@ class LiveObjectList {
static Object* PrintObj(int obj_id);
private:
-
struct Element {
int id_;
HeapObject* obj_;
@@ -224,7 +223,6 @@ class LiveObjectList {
// Helper class for updating the LiveObjectList HeapObject pointers.
class UpdateLiveObjectListVisitor: public ObjectVisitor {
public:
-
void VisitPointer(Object** p) { UpdatePointer(p); }
void VisitPointers(Object** start, Object** end) {
@@ -319,4 +317,3 @@ class LiveObjectList {
} } // namespace v8::internal
#endif // V8_LIVEOBJECTLIST_H_
-
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 27e654d5..7bd7baa2 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -125,7 +125,7 @@ void Log::Initialize() {
stream.Put(*p);
}
}
- SmartPointer<const char> expanded = stream.ToCString();
+ SmartArrayPointer<const char> expanded = stream.ToCString();
OpenFile(*expanded);
} else {
OpenFile(FLAG_logfile);
diff --git a/src/log-utils.h b/src/log-utils.h
index 2b20a01b..d0cb8289 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -141,7 +141,6 @@ class LogMessageBuilder BASE_EMBEDDED {
void WriteToLogFile();
private:
-
Log* log_;
ScopedLock sl;
int pos_;
diff --git a/src/log.cc b/src/log.cc
index dedf7e90..3d66b5fb 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -617,7 +617,7 @@ void Logger::ApiEvent(const char* format, ...) {
void Logger::ApiNamedSecurityCheck(Object* key) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
if (key->IsString()) {
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,check-security,\"%s\"\n", *str);
} else if (key->IsUndefined()) {
@@ -762,9 +762,9 @@ void Logger::ApiNamedPropertyAccess(const char* tag,
ASSERT(name->IsString());
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- SmartPointer<char> property_name =
+ SmartArrayPointer<char> property_name =
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
}
@@ -774,7 +774,7 @@ void Logger::ApiIndexedPropertyAccess(const char* tag,
uint32_t index) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
}
@@ -782,7 +782,7 @@ void Logger::ApiIndexedPropertyAccess(const char* tag,
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = object->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
}
@@ -836,7 +836,7 @@ void Logger::CallbackEventInternal(const char* prefix, const char* name,
void Logger::CallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("", *str, entry_point);
}
@@ -844,7 +844,7 @@ void Logger::CallbackEvent(String* name, Address entry_point) {
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("get ", *str, entry_point);
}
@@ -852,7 +852,7 @@ void Logger::GetterCallbackEvent(String* name, Address entry_point) {
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("set ", *str, entry_point);
}
@@ -957,7 +957,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
return;
LogMessageBuilder msg(this);
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
@@ -998,9 +998,9 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- SmartPointer<char> name =
+ SmartArrayPointer<char> name =
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- SmartPointer<char> sourcestr =
+ SmartArrayPointer<char> sourcestr =
source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
@@ -1527,6 +1527,51 @@ void Logger::LogCodeObjects() {
}
+void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code) {
+ Handle<String> func_name(shared->DebugName());
+ if (shared->script()->IsScript()) {
+ Handle<Script> script(Script::cast(shared->script()));
+ if (script->name()->IsString()) {
+ Handle<String> script_name(String::cast(script->name()));
+ int line_num = GetScriptLineNumber(script, shared->start_position());
+ if (line_num > 0) {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared,
+ *script_name, line_num + 1));
+ } else {
+ // Can't distinguish eval and script here, so always use Script.
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+ *code, *shared, *script_name));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared, *func_name));
+ }
+ } else if (shared->IsApiFunction()) {
+ // API function.
+ FunctionTemplateInfo* fun_data = shared->get_api_func_data();
+ Object* raw_call_data = fun_data->call_code();
+ if (!raw_call_data->IsUndefined()) {
+ CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+ Object* callback_obj = call_data->callback();
+ Address entry_point = v8::ToCData<Address>(callback_obj);
+ PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
+ }
+}
+
+
void Logger::LogCompiledFunctions() {
HandleScope scope;
const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
@@ -1540,48 +1585,7 @@ void Logger::LogCompiledFunctions() {
if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
Builtins::kLazyCompile))
continue;
- Handle<SharedFunctionInfo> shared = sfis[i];
- Handle<String> func_name(shared->DebugName());
- if (shared->script()->IsScript()) {
- Handle<Script> script(Script::cast(shared->script()));
- if (script->name()->IsString()) {
- Handle<String> script_name(String::cast(script->name()));
- int line_num = GetScriptLineNumber(script, shared->start_position());
- if (line_num > 0) {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared,
- *script_name, line_num + 1));
- } else {
- // Can't distinguish eval and script here, so always use Script.
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *code_objects[i], *shared, *script_name));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared, *func_name));
- }
- } else if (shared->IsApiFunction()) {
- // API function.
- FunctionTemplateInfo* fun_data = shared->get_api_func_data();
- Object* raw_call_data = fun_data->call_code();
- if (!raw_call_data->IsUndefined()) {
- CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
- Object* callback_obj = call_data->callback();
- Address entry_point = v8::ToCData<Address>(callback_obj);
- PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::LAZY_COMPILE_TAG, *code_objects[i],
- *shared, *func_name));
- }
+ LogExistingFunction(sfis[i], code_objects[i]);
}
}
diff --git a/src/log.h b/src/log.h
index 31d84041..50358ce5 100644
--- a/src/log.h
+++ b/src/log.h
@@ -281,6 +281,8 @@ class Logger {
void ResumeProfiler();
bool IsProfilerPaused();
+ void LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code);
// Logs all compiled functions found in the heap.
void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
diff --git a/src/macros.py b/src/macros.py
index 5ba7ac3a..7a493ca7 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -116,13 +116,21 @@ macro FLOOR(arg) = $floor(arg);
# Macro for ECMAScript 5 queries of the type:
# "Type(O) is object."
-# This is the same as being either a function or an object in V8 terminology.
+# This is the same as being either a function or an object in V8 terminology
+# (including proxies).
# In addition, an undetectable object is also included by this.
-macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
+macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
+
+# Macro for ECMAScript 5 queries of the type:
+# "IsCallable(O)"
+# We assume here that this is the same as being either a function or a function
+# proxy. That ignores host objects with [[Call]] methods, but in most situations
+# we cannot handle those anyway.
+macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
-macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || arg - arg == 0);
+macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
@@ -170,7 +178,7 @@ macro CAPTURE(index) = (3 + (index));
const CAPTURE0 = 3;
const CAPTURE1 = 4;
-# PropertyDescriptor return value indices - must match
+# PropertyDescriptor return value indices - must match
# PropertyDescriptorIndices in runtime.cc.
const IS_ACCESSOR_INDEX = 0;
const VALUE_INDEX = 1;
@@ -179,3 +187,17 @@ const SETTER_INDEX = 3;
const WRITABLE_INDEX = 4;
const ENUMERABLE_INDEX = 5;
const CONFIGURABLE_INDEX = 6;
+
+# For messages.js
+# Matches Script::Type from objects.h
+const TYPE_NATIVE = 0;
+const TYPE_EXTENSION = 1;
+const TYPE_NORMAL = 2;
+
+# Matches Script::CompilationType from objects.h
+const COMPILATION_TYPE_HOST = 0;
+const COMPILATION_TYPE_EVAL = 1;
+const COMPILATION_TYPE_JSON = 2;
+
+# Matches Messages::kNoLineNumberInfo from v8.h
+const kNoLineNumberInfo = 0;
diff --git a/src/math.js b/src/math.js
index 70b8c57c..b5a6d181 100644
--- a/src/math.js
+++ b/src/math.js
@@ -38,7 +38,7 @@ const $abs = MathAbs;
function MathConstructor() {}
%FunctionSetInstanceClassName(MathConstructor, 'Math');
const $Math = new MathConstructor();
-$Math.__proto__ = global.Object.prototype;
+$Math.__proto__ = $Object.prototype;
%SetProperty(global, "Math", $Math, DONT_ENUM);
// ECMA 262 - 15.8.2.1
@@ -195,8 +195,9 @@ function MathTan(x) {
// -------------------------------------------------------------------
-function SetupMath() {
- // Setup math constants.
+function SetUpMath() {
+ %CheckIsBootstrapping();
+ // Set up math constants.
// ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8);
%SetProperty($Math,
@@ -236,7 +237,7 @@ function SetupMath() {
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Math);
- // Setup non-enumerable functions of the Math object and
+ // Set up non-enumerable functions of the Math object and
// set their names.
InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
"random", MathRandom,
@@ -258,7 +259,6 @@ function SetupMath() {
"max", MathMax,
"min", MathMin
));
-};
-
+}
-SetupMath();
+SetUpMath();
diff --git a/src/messages.cc b/src/messages.cc
index 4cbf0af7..b6ad5ac3 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -41,13 +41,13 @@ namespace internal {
// by default.
void MessageHandler::DefaultMessageReport(const MessageLocation* loc,
Handle<Object> message_obj) {
- SmartPointer<char> str = GetLocalizedMessage(message_obj);
+ SmartArrayPointer<char> str = GetLocalizedMessage(message_obj);
if (loc == NULL) {
PrintF("%s\n", *str);
} else {
HandleScope scope;
Handle<Object> data(loc->script()->name());
- SmartPointer<char> data_str;
+ SmartArrayPointer<char> data_str;
if (data->IsString())
data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>",
@@ -170,7 +170,8 @@ Handle<String> MessageHandler::GetMessage(Handle<Object> data) {
}
-SmartPointer<char> MessageHandler::GetLocalizedMessage(Handle<Object> data) {
+SmartArrayPointer<char> MessageHandler::GetLocalizedMessage(
+ Handle<Object> data) {
HandleScope scope;
return GetMessage(data)->ToCString(DISALLOW_NULLS);
}
diff --git a/src/messages.h b/src/messages.h
index fc2162de..358509ec 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -105,7 +105,7 @@ class MessageHandler {
static void DefaultMessageReport(const MessageLocation* loc,
Handle<Object> message_obj);
static Handle<String> GetMessage(Handle<Object> data);
- static SmartPointer<char> GetLocalizedMessage(Handle<Object> data);
+ static SmartArrayPointer<char> GetLocalizedMessage(Handle<Object> data);
};
} } // namespace v8::internal
diff --git a/src/messages.js b/src/messages.js
index 845ca077..a9993af2 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -28,27 +28,14 @@
// -------------------------------------------------------------------
//
-// Matches Script::Type from objects.h
-var TYPE_NATIVE = 0;
-var TYPE_EXTENSION = 1;
-var TYPE_NORMAL = 2;
-
-// Matches Script::CompilationType from objects.h
-var COMPILATION_TYPE_HOST = 0;
-var COMPILATION_TYPE_EVAL = 1;
-var COMPILATION_TYPE_JSON = 2;
-
-// Matches Messages::kNoLineNumberInfo from v8.h
-var kNoLineNumberInfo = 0;
-
// If this object gets passed to an error constructor the error will
// get an accessor for .message that constructs a descriptive error
// message on access.
-var kAddMessageAccessorsMarker = { };
+const kAddMessageAccessorsMarker = { };
-var kMessages = 0;
-
-var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ];
+// This will be lazily initialized when first needed (and forcibly
+// overwritten even though it's const).
+const kMessages = 0;
function FormatString(format, message) {
var args = %MessageGetArguments(message);
@@ -56,14 +43,16 @@ function FormatString(format, message) {
var arg_num = 0;
for (var i = 0; i < format.length; i++) {
var str = format[i];
- for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) {
- if (str == kReplacementMarkers[arg_num]) {
+ if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
+ // Two-char string starts with "%".
+ var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
+ if (arg_num < 4) {
+ // str is one of %0, %1, %2 or %3.
try {
str = ToDetailString(args[arg_num]);
} catch (e) {
str = "#<error>";
}
- break;
}
}
result += str;
@@ -102,18 +91,16 @@ function ToStringCheckErrorObject(obj) {
function ToDetailString(obj) {
- if (obj != null && IS_OBJECT(obj) &&
- obj.toString === $Object.prototype.toString) {
+ if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
var constructor = obj.constructor;
- if (!constructor) return ToStringCheckErrorObject(obj);
- var constructorName = constructor.name;
- if (!constructorName || !IS_STRING(constructorName)) {
- return ToStringCheckErrorObject(obj);
+ if (typeof constructor == "function") {
+ var constructorName = constructor.name;
+ if (IS_STRING(constructorName) && constructorName !== "") {
+ return "#<" + constructorName + ">";
+ }
}
- return "#<" + constructorName + ">";
- } else {
- return ToStringCheckErrorObject(obj);
}
+ return ToStringCheckErrorObject(obj);
}
@@ -129,10 +116,11 @@ function MakeGenericError(constructor, type, args) {
/**
- * Setup the Script function and constructor.
+ * Set up the Script function and constructor.
*/
%FunctionSetInstanceClassName(Script, 'Script');
-%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
+%SetProperty(Script.prototype, 'constructor', Script,
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetCode(Script, function(x) {
// Script objects can only be created by the VM.
throw new $Error("Not supported");
@@ -142,118 +130,135 @@ function MakeGenericError(constructor, type, args) {
// Helper functions; called from the runtime system.
function FormatMessage(message) {
if (kMessages === 0) {
- kMessages = {
+ var messagesDictionary = [
// Error
- cyclic_proto: ["Cyclic __proto__ value"],
- code_gen_from_strings: ["Code generation from strings disallowed for this context"],
+ "cyclic_proto", ["Cyclic __proto__ value"],
+ "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
// TypeError
- unexpected_token: ["Unexpected token ", "%0"],
- unexpected_token_number: ["Unexpected number"],
- unexpected_token_string: ["Unexpected string"],
- unexpected_token_identifier: ["Unexpected identifier"],
- unexpected_reserved: ["Unexpected reserved word"],
- unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
- unexpected_eos: ["Unexpected end of input"],
- malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
- unterminated_regexp: ["Invalid regular expression: missing /"],
- regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
- incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
- invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
- invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"],
- invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
- invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
- multiple_defaults_in_switch: ["More than one default clause in switch statement"],
- newline_after_throw: ["Illegal newline after throw"],
- redeclaration: ["%0", " '", "%1", "' has already been declared"],
- no_catch_or_finally: ["Missing catch or finally after try"],
- unknown_label: ["Undefined label '", "%0", "'"],
- uncaught_exception: ["Uncaught ", "%0"],
- stack_trace: ["Stack Trace:\n", "%0"],
- called_non_callable: ["%0", " is not a function"],
- undefined_method: ["Object ", "%1", " has no method '", "%0", "'"],
- property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"],
- cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
- not_constructor: ["%0", " is not a constructor"],
- not_defined: ["%0", " is not defined"],
- non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
- non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
- non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"],
- with_expression: ["%0", " has no properties"],
- illegal_invocation: ["Illegal invocation"],
- no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
- apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
- apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"],
- invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
- instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
- instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
- null_to_object: ["Cannot convert null to object"],
- reduce_no_initial: ["Reduce of empty array with no initial value"],
- getter_must_be_callable: ["Getter must be a function: ", "%0"],
- setter_must_be_callable: ["Setter must be a function: ", "%0"],
- value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"],
- proto_object_or_null: ["Object prototype may only be an Object or null"],
- property_desc_object: ["Property description must be an object: ", "%0"],
- redefine_disallowed: ["Cannot redefine property: ", "%0"],
- define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."],
- non_extensible_proto: ["%0", " is not extensible"],
- handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
- handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
- handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
- handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
- handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
- proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
- proxy_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"],
- proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"],
- invalid_weakmap_key: ["Invalid value used as weak map key"],
+ "unexpected_token", ["Unexpected token ", "%0"],
+ "unexpected_token_number", ["Unexpected number"],
+ "unexpected_token_string", ["Unexpected string"],
+ "unexpected_token_identifier", ["Unexpected identifier"],
+ "unexpected_reserved", ["Unexpected reserved word"],
+ "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
+ "unexpected_eos", ["Unexpected end of input"],
+ "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
+ "unterminated_regexp", ["Invalid regular expression: missing /"],
+ "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
+ "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
+ "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"],
+ "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"],
+ "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"],
+ "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"],
+ "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
+ "newline_after_throw", ["Illegal newline after throw"],
+ "redeclaration", ["%0", " '", "%1", "' has already been declared"],
+ "no_catch_or_finally", ["Missing catch or finally after try"],
+ "unknown_label", ["Undefined label '", "%0", "'"],
+ "uncaught_exception", ["Uncaught ", "%0"],
+ "stack_trace", ["Stack Trace:\n", "%0"],
+ "called_non_callable", ["%0", " is not a function"],
+ "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
+ "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
+ "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
+ "not_constructor", ["%0", " is not a constructor"],
+ "not_defined", ["%0", " is not defined"],
+ "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
+ "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
+ "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
+ "with_expression", ["%0", " has no properties"],
+ "illegal_invocation", ["Illegal invocation"],
+ "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
+ "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
+ "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"],
+ "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
+ "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
+ "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
+ "null_to_object", ["Cannot convert null to object"],
+ "reduce_no_initial", ["Reduce of empty array with no initial value"],
+ "getter_must_be_callable", ["Getter must be a function: ", "%0"],
+ "setter_must_be_callable", ["Setter must be a function: ", "%0"],
+ "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
+ "proto_object_or_null", ["Object prototype may only be an Object or null"],
+ "property_desc_object", ["Property description must be an object: ", "%0"],
+ "redefine_disallowed", ["Cannot redefine property: ", "%0"],
+ "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
+ "non_extensible_proto", ["%0", " is not extensible"],
+ "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
+ "trap_function_expected", ["Proxy.", "%0", " called with non-function for ", "%1", " trap"],
+ "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
+ "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
+ "handler_returned_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
+ "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
+ "proxy_prop_not_configurable", ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
+ "proxy_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"],
+ "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"],
+ "invalid_weakmap_key", ["Invalid value used as weak map key"],
// RangeError
- invalid_array_length: ["Invalid array length"],
- stack_overflow: ["Maximum call stack size exceeded"],
+ "invalid_array_length", ["Invalid array length"],
+ "stack_overflow", ["Maximum call stack size exceeded"],
// SyntaxError
- unable_to_parse: ["Parse error"],
- invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
- invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
- illegal_break: ["Illegal break statement"],
- illegal_continue: ["Illegal continue statement"],
- illegal_return: ["Illegal return statement"],
- error_loading_debugger: ["Error loading debugger"],
- no_input_to_regexp: ["No input to ", "%0"],
- invalid_json: ["String '", "%0", "' is not valid JSON"],
- circular_structure: ["Converting circular structure to JSON"],
- obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"],
- called_on_null_or_undefined: ["%0", " called on null or undefined"],
- array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
- object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
- illegal_access: ["Illegal access"],
- invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
- strict_mode_with: ["Strict mode code may not include a with statement"],
- strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"],
- too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"],
- too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"],
- too_many_variables: ["Too many variables declared (only 32767 allowed)"],
- strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"],
- strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
- strict_var_name: ["Variable name may not be eval or arguments in strict mode"],
- strict_function_name: ["Function name may not be eval or arguments in strict mode"],
- strict_octal_literal: ["Octal literals are not allowed in strict mode."],
- strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
- accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
- accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
- strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"],
- strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
- strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
- strict_reserved_word: ["Use of future reserved word in strict mode"],
- strict_delete: ["Delete of an unqualified identifier in strict mode."],
- strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
- strict_const: ["Use of const in strict mode."],
- strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
- strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
- strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
- strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
- strict_caller: ["Illegal access to a strict mode caller function."],
- unprotected_let: ["Illegal let declaration in unprotected statement context."],
- cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
- redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
- };
+ "unable_to_parse", ["Parse error"],
+ "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
+ "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
+ "illegal_break", ["Illegal break statement"],
+ "illegal_continue", ["Illegal continue statement"],
+ "illegal_return", ["Illegal return statement"],
+ "error_loading_debugger", ["Error loading debugger"],
+ "no_input_to_regexp", ["No input to ", "%0"],
+ "invalid_json", ["String '", "%0", "' is not valid JSON"],
+ "circular_structure", ["Converting circular structure to JSON"],
+ "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
+ "called_on_null_or_undefined", ["%0", " called on null or undefined"],
+ "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
+ "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
+ "illegal_access", ["Illegal access"],
+ "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
+ "strict_mode_with", ["Strict mode code may not include a with statement"],
+ "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
+ "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
+ "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
+ "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
+ "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
+ "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
+ "strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
+ "strict_function_name", ["Function name may not be eval or arguments in strict mode"],
+ "strict_octal_literal", ["Octal literals are not allowed in strict mode."],
+ "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"],
+ "accessor_data_property", ["Object literal may not have data and accessor property with the same name"],
+ "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"],
+ "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"],
+ "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
+ "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
+ "strict_reserved_word", ["Use of future reserved word in strict mode"],
+ "strict_delete", ["Delete of an unqualified identifier in strict mode."],
+ "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
+ "strict_const", ["Use of const in strict mode."],
+ "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
+ "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"],
+ "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"],
+ "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
+ "strict_caller", ["Illegal access to a strict mode caller function."],
+ "unprotected_let", ["Illegal let declaration in unprotected statement context."],
+ "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
+ "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
+ ];
+ var messages = { __proto__ : null };
+ var desc = new PropertyDescriptor();
+ desc.setConfigurable(false);
+ desc.setEnumerable(false);
+ desc.setWritable(false);
+ for (var i = 0; i < messagesDictionary.length; i += 2) {
+ var key = messagesDictionary[i];
+ var format = messagesDictionary[i + 1];
+ ObjectFreeze(format);
+ desc.setValue(format);
+ DefineOwnProperty(messages, key, desc);
+ }
+ %PreventExtensions(messages);
+ %IgnoreAttributesAndSetProperty(builtins, "kMessages",
+ messages,
+ DONT_DELETE | DONT_ENUM | READ_ONLY);
}
var message_type = %MessageGetType(message);
var format = kMessages[message_type];
@@ -319,7 +324,7 @@ function MakeError(type, args) {
* @return {number} 0 if input too small, -1 if input too large,
else the line number.
*/
-Script.prototype.lineFromPosition = function(position) {
+function ScriptLineFromPosition(position) {
var lower = 0;
var upper = this.lineCount() - 1;
var line_ends = this.line_ends;
@@ -358,8 +363,8 @@ Script.prototype.lineFromPosition = function(position) {
* @return {SourceLocation}
* If line is negative or not in the source null is returned.
*/
-Script.prototype.locationFromPosition = function (position,
- include_resource_offset) {
+function ScriptLocationFromPosition(position,
+ include_resource_offset) {
var line = this.lineFromPosition(position);
if (line == -1) return null;
@@ -367,7 +372,9 @@ Script.prototype.locationFromPosition = function (position,
var line_ends = this.line_ends;
var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line];
- if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--;
+ if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
+ end--;
+ }
var column = position - start;
// Adjust according to the offset within the resource.
@@ -392,11 +399,12 @@ Script.prototype.locationFromPosition = function (position,
* @param {number} opt_line The line within the source. Default value is 0
* @param {number} opt_column The column in within the line. Default value is 0
* @param {number} opt_offset_position The offset from the begining of the
- * source from where the line and column calculation starts. Default value is 0
+ * source from where the line and column calculation starts.
+ * Default value is 0
* @return {SourceLocation}
* If line is negative or not in the source null is returned.
*/
-Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) {
+function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
// Default is the first line in the script. Lines in the script is relative
// to the offset within the resource.
var line = 0;
@@ -438,7 +446,7 @@ Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_p
* @return {SourceSlice} The source slice or null of the parameters where
* invalid
*/
-Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+function ScriptSourceSlice(opt_from_line, opt_to_line) {
var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
@@ -465,7 +473,7 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
}
-Script.prototype.sourceLine = function (opt_line) {
+function ScriptSourceLine(opt_line) {
// Default is the first line in the script. Lines in the script are relative
// to the offset within the resource.
var line = 0;
@@ -491,7 +499,7 @@ Script.prototype.sourceLine = function (opt_line) {
* @return {number}
* Number of source lines.
*/
-Script.prototype.lineCount = function() {
+function ScriptLineCount() {
// Return number of source lines.
return this.line_ends.length;
};
@@ -507,9 +515,10 @@ Script.prototype.lineCount = function() {
* @return {?string} script name if present, value for //@ sourceURL comment
* otherwise.
*/
-Script.prototype.nameOrSourceURL = function() {
- if (this.name)
+function ScriptNameOrSourceURL() {
+ if (this.name) {
return this.name;
+ }
// TODO(608): the spaces in a regexp below had to be escaped as \040
// because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to
@@ -535,6 +544,20 @@ Script.prototype.nameOrSourceURL = function() {
}
+SetUpLockedPrototype(Script,
+ $Array("source", "name", "line_ends", "line_offset", "column_offset"),
+ $Array(
+ "lineFromPosition", ScriptLineFromPosition,
+ "locationFromPosition", ScriptLocationFromPosition,
+ "locationFromLine", ScriptLocationFromLine,
+ "sourceSlice", ScriptSourceSlice,
+ "sourceLine", ScriptSourceLine,
+ "lineCount", ScriptLineCount,
+ "nameOrSourceURL", ScriptNameOrSourceURL
+ )
+);
+
+
/**
* Class for source location. A source location is a position within some
* source with the following properties:
@@ -565,8 +588,6 @@ function SourceLocation(script, position, line, column, start, end) {
this.end = end;
}
-SourceLocation.prototype.__proto__ = null;
-
const kLineLengthLimit = 78;
/**
@@ -577,7 +598,7 @@ const kLineLengthLimit = 78;
* @param {number} opt_before The number of characters to prefer before the
* position with a default value of 10 less that the limit
*/
-SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
+function SourceLocationRestrict(opt_limit, opt_before) {
// Find the actual limit to use.
var limit;
var before;
@@ -624,11 +645,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
* @return {String}
* Source text for this location.
*/
-SourceLocation.prototype.sourceText = function () {
+function SourceLocationSourceText() {
return %_CallFunction(this.script.source, this.start, this.end, StringSubstring);
};
+SetUpLockedPrototype(SourceLocation,
+ $Array("script", "position", "line", "column", "start", "end"),
+ $Array(
+ "restrict", SourceLocationRestrict,
+ "sourceText", SourceLocationSourceText
+ )
+);
+
+
/**
* Class for a source slice. A source slice is a part of a script source with
* the following properties:
@@ -655,20 +685,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) {
this.to_position = to_position;
}
-SourceSlice.prototype.__proto__ = null;
-
/**
* Get the source text for a SourceSlice
* @return {String} Source text for this slice. The last line will include
* the line terminating characters (if any)
*/
-SourceSlice.prototype.sourceText = function () {
+function SourceSliceSourceText() {
return %_CallFunction(this.script.source,
this.from_position,
this.to_position,
StringSubstring);
};
+SetUpLockedPrototype(SourceSlice,
+ $Array("script", "from_line", "to_line", "from_position", "to_position"),
+ $Array("sourceText", SourceSliceSourceText)
+);
+
// Returns the offset of the given position within the containing
// line.
@@ -723,13 +756,11 @@ function CallSite(receiver, fun, pos) {
this.pos = pos;
}
-CallSite.prototype.__proto__ = null;
-
-CallSite.prototype.getThis = function () {
+function CallSiteGetThis() {
return this.receiver;
};
-CallSite.prototype.getTypeName = function () {
+function CallSiteGetTypeName() {
var constructor = this.receiver.constructor;
if (!constructor) {
return %_CallFunction(this.receiver, ObjectToString);
@@ -741,33 +772,33 @@ CallSite.prototype.getTypeName = function () {
return constructorName;
};
-CallSite.prototype.isToplevel = function () {
+function CallSiteIsToplevel() {
if (this.receiver == null) {
return true;
}
return IS_GLOBAL(this.receiver);
};
-CallSite.prototype.isEval = function () {
+function CallSiteIsEval() {
var script = %FunctionGetScript(this.fun);
return script && script.compilation_type == COMPILATION_TYPE_EVAL;
};
-CallSite.prototype.getEvalOrigin = function () {
+function CallSiteGetEvalOrigin() {
var script = %FunctionGetScript(this.fun);
return FormatEvalOrigin(script);
};
-CallSite.prototype.getScriptNameOrSourceURL = function () {
+function CallSiteGetScriptNameOrSourceURL() {
var script = %FunctionGetScript(this.fun);
return script ? script.nameOrSourceURL() : null;
};
-CallSite.prototype.getFunction = function () {
+function CallSiteGetFunction() {
return this.fun;
};
-CallSite.prototype.getFunctionName = function () {
+function CallSiteGetFunctionName() {
// See if the function knows its own name
var name = this.fun.name;
if (name) {
@@ -783,7 +814,7 @@ CallSite.prototype.getFunctionName = function () {
return null;
};
-CallSite.prototype.getMethodName = function () {
+function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds
// this function.
var ownName = this.fun.name;
@@ -813,12 +844,12 @@ CallSite.prototype.getMethodName = function () {
return null;
};
-CallSite.prototype.getFileName = function () {
+function CallSiteGetFileName() {
var script = %FunctionGetScript(this.fun);
return script ? script.name : null;
};
-CallSite.prototype.getLineNumber = function () {
+function CallSiteGetLineNumber() {
if (this.pos == -1) {
return null;
}
@@ -830,7 +861,7 @@ CallSite.prototype.getLineNumber = function () {
return location ? location.line + 1 : null;
};
-CallSite.prototype.getColumnNumber = function () {
+function CallSiteGetColumnNumber() {
if (this.pos == -1) {
return null;
}
@@ -842,16 +873,16 @@ CallSite.prototype.getColumnNumber = function () {
return location ? location.column + 1: null;
};
-CallSite.prototype.isNative = function () {
+function CallSiteIsNative() {
var script = %FunctionGetScript(this.fun);
return script ? (script.type == TYPE_NATIVE) : false;
};
-CallSite.prototype.getPosition = function () {
+function CallSiteGetPosition() {
return this.pos;
};
-CallSite.prototype.isConstructor = function () {
+function CallSiteIsConstructor() {
var constructor = this.receiver ? this.receiver.constructor : null;
if (!constructor) {
return false;
@@ -859,6 +890,25 @@ CallSite.prototype.isConstructor = function () {
return this.fun === constructor;
};
+SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
+ "getThis", CallSiteGetThis,
+ "getTypeName", CallSiteGetTypeName,
+ "isToplevel", CallSiteIsToplevel,
+ "isEval", CallSiteIsEval,
+ "getEvalOrigin", CallSiteGetEvalOrigin,
+ "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
+ "getFunction", CallSiteGetFunction,
+ "getFunctionName", CallSiteGetFunctionName,
+ "getMethodName", CallSiteGetMethodName,
+ "getFileName", CallSiteGetFileName,
+ "getLineNumber", CallSiteGetLineNumber,
+ "getColumnNumber", CallSiteGetColumnNumber,
+ "isNative", CallSiteIsNative,
+ "getPosition", CallSiteGetPosition,
+ "isConstructor", CallSiteIsConstructor
+));
+
+
function FormatEvalOrigin(script) {
var sourceURL = script.nameOrSourceURL();
if (sourceURL) {
@@ -1000,63 +1050,6 @@ function FormatRawStackTrace(error, raw_stack) {
}
}
-function DefineError(f) {
- // Store the error function in both the global object
- // and the runtime object. The function is fetched
- // from the runtime object when throwing errors from
- // within the runtime system to avoid strange side
- // effects when overwriting the error functions from
- // user code.
- var name = f.name;
- %SetProperty(global, name, f, DONT_ENUM);
- this['$' + name] = f;
- // Configure the error function.
- if (name == 'Error') {
- // The prototype of the Error object must itself be an error.
- // However, it can't be an instance of the Error object because
- // it hasn't been properly configured yet. Instead we create a
- // special not-a-true-error-but-close-enough object.
- function ErrorPrototype() {}
- %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
- %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
- %FunctionSetPrototype(f, new ErrorPrototype());
- } else {
- %FunctionSetPrototype(f, new $Error());
- }
- %FunctionSetInstanceClassName(f, 'Error');
- %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
- // The name property on the prototype of error objects is not
- // specified as being read-one and dont-delete. However, allowing
- // overwriting allows leaks of error objects between script blocks
- // in the same context in a browser setting. Therefore we fix the
- // name.
- %SetProperty(f.prototype, "name", name, DONT_ENUM | DONT_DELETE | READ_ONLY);
- %SetCode(f, function(m) {
- if (%_IsConstructCall()) {
- // Define all the expected properties directly on the error
- // object. This avoids going through getters and setters defined
- // on prototype objects.
- %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
- %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
- %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
- if (m === kAddMessageAccessorsMarker) {
- // DefineOneShotAccessor always inserts a message property and
- // ignores setters.
- DefineOneShotAccessor(this, 'message', function (obj) {
- return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
- });
- } else if (!IS_UNDEFINED(m)) {
- %IgnoreAttributesAndSetProperty(this,
- 'message',
- ToString(m),
- DONT_ENUM);
- }
- captureStackTrace(this, f);
- } else {
- return new f(m);
- }
- });
-}
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
@@ -1072,52 +1065,100 @@ function captureStackTrace(obj, cons_opt) {
});
};
-$Math.__proto__ = global.Object.prototype;
-// DefineError is a native function. Use explicit receiver. Otherwise
-// the receiver will be 'undefined'.
-this.DefineError(function Error() { });
-this.DefineError(function TypeError() { });
-this.DefineError(function RangeError() { });
-this.DefineError(function SyntaxError() { });
-this.DefineError(function ReferenceError() { });
-this.DefineError(function EvalError() { });
-this.DefineError(function URIError() { });
+function SetUpError() {
+ // Define special error type constructors.
+
+ function DefineError(f) {
+ // Store the error function in both the global object
+ // and the runtime object. The function is fetched
+ // from the runtime object when throwing errors from
+ // within the runtime system to avoid strange side
+ // effects when overwriting the error functions from
+ // user code.
+ var name = f.name;
+ %SetProperty(global, name, f, DONT_ENUM);
+ %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ // Configure the error function.
+ if (name == 'Error') {
+ // The prototype of the Error object must itself be an error.
+ // However, it can't be an instance of the Error object because
+ // it hasn't been properly configured yet. Instead we create a
+ // special not-a-true-error-but-close-enough object.
+ function ErrorPrototype() {}
+ %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
+ %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
+ %FunctionSetPrototype(f, new ErrorPrototype());
+ } else {
+ %FunctionSetPrototype(f, new $Error());
+ }
+ %FunctionSetInstanceClassName(f, 'Error');
+ %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
+ // The name property on the prototype of error objects is not
+ // specified as being read-one and dont-delete. However, allowing
+ // overwriting allows leaks of error objects between script blocks
+ // in the same context in a browser setting. Therefore we fix the
+ // name.
+ %SetProperty(f.prototype, "name", name,
+ DONT_ENUM | DONT_DELETE | READ_ONLY) ;
+ %SetCode(f, function(m) {
+ if (%_IsConstructCall()) {
+ // Define all the expected properties directly on the error
+ // object. This avoids going through getters and setters defined
+ // on prototype objects.
+ %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
+ %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
+ %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
+ if (m === kAddMessageAccessorsMarker) {
+ // DefineOneShotAccessor always inserts a message property and
+ // ignores setters.
+ DefineOneShotAccessor(this, 'message', function (obj) {
+ return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
+ });
+ } else if (!IS_UNDEFINED(m)) {
+ %IgnoreAttributesAndSetProperty(this,
+ 'message',
+ ToString(m),
+ DONT_ENUM);
+ }
+ captureStackTrace(this, f);
+ } else {
+ return new f(m);
+ }
+ });
+ }
-$Error.captureStackTrace = captureStackTrace;
+ DefineError(function Error() { });
+ DefineError(function TypeError() { });
+ DefineError(function RangeError() { });
+ DefineError(function SyntaxError() { });
+ DefineError(function ReferenceError() { });
+ DefineError(function EvalError() { });
+ DefineError(function URIError() { });
+}
-// Setup extra properties of the Error.prototype object.
-function setErrorMessage() {
- var desc = {value: '',
- enumerable: false,
- configurable: true,
- writable: true };
- DefineOwnProperty($Error.prototype,
- 'message',
- ToPropertyDescriptor(desc),
- true);
+SetUpError();
-}
+$Error.captureStackTrace = captureStackTrace;
-setErrorMessage();
+%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
// Global list of error objects visited during errorToString. This is
// used to detect cycles in error toString formatting.
-var visited_errors = new $Array();
-var cyclic_error_marker = new $Object();
+const visited_errors = new InternalArray();
+const cyclic_error_marker = new $Object();
-function errorToStringDetectCycle() {
- if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker;
+function errorToStringDetectCycle(error) {
+ if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try {
- var type = this.type;
- if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) {
- var formatted = FormatMessage(%NewMessageObject(type, this.arguments));
- return this.name + ": " + formatted;
+ var type = error.type;
+ var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
+ if (type && !hasMessage) {
+ var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
+ return error.name + ": " + formatted;
}
- var message = %_CallFunction(this, "message", ObjectHasOwnProperty)
- ? (": " + this.message)
- : "";
- return this.name + message;
+ var message = hasMessage ? (": " + error.message) : "";
+ return error.name + message;
} finally {
visited_errors.length = visited_errors.length - 1;
}
@@ -1133,7 +1174,7 @@ function errorToString() {
function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
try {
- return %_CallFunction(this, errorToStringDetectCycle);
+ return errorToStringDetectCycle(this);
} catch(e) {
// If this error message was encountered already return the empty
// string for it instead of recursively formatting it.
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index b5ffe739..c4c4fd25 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -83,6 +83,14 @@ bool Operand::is_reg() const {
// RelocInfo.
void RelocInfo::apply(intptr_t delta) {
+ if (IsCodeTarget(rmode_)) {
+ uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask;
+ uint32_t scope2 = reinterpret_cast<uint32_t>(pc_) & ~kImm28Mask;
+
+ if (scope1 != scope2) {
+ Assembler::JumpLabelToJumpRegister(pc_);
+ }
+ }
if (IsInternalReference(rmode_)) {
// Absolute code pointer inside code object moves with the code object.
byte* p = reinterpret_cast<byte*>(pc_);
@@ -218,8 +226,9 @@ bool RelocInfo::IsPatchedReturnSequence() {
Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
(instr1 & kOpcodeMask) == ORI &&
- (instr2 & kOpcodeMask) == SPECIAL &&
- (instr2 & kFunctionFieldMask) == JALR);
+ ((instr2 & kOpcodeMask) == JAL ||
+ ((instr2 & kOpcodeMask) == SPECIAL &&
+ (instr2 & kFunctionFieldMask) == JALR)));
return patched_return;
}
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index 28ac5577..e01a0ca7 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -49,11 +49,47 @@ bool CpuFeatures::initialized_ = false;
unsigned CpuFeatures::supported_ = 0;
unsigned CpuFeatures::found_by_runtime_probing_ = 0;
+
+// Get the CPU features enabled by the build. For cross compilation the
+// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
+// can be defined to enable FPU instructions when building the
+// snapshot.
+static uint64_t CpuFeaturesImpliedByCompiler() {
+ uint64_t answer = 0;
+#ifdef CAN_USE_FPU_INSTRUCTIONS
+ answer |= 1u << FPU;
+#endif // def CAN_USE_FPU_INSTRUCTIONS
+
+#ifdef __mips__
+ // If the compiler is allowed to use FPU then we can use FPU too in our code
+ // generation even when generating snapshots. This won't work for cross
+ // compilation.
+#if(defined(__mips_hard_float) && __mips_hard_float != 0)
+ answer |= 1u << FPU;
+#endif // defined(__mips_hard_float) && __mips_hard_float != 0
+#endif // def __mips__
+
+ return answer;
+}
+
+
void CpuFeatures::Probe() {
ASSERT(!initialized_);
#ifdef DEBUG
initialized_ = true;
#endif
+
+ // Get the features implied by the OS and the compiler settings. This is the
+ // minimal set of features which is also allowed for generated code in the
+ // snapshot.
+ supported_ |= OS::CpuFeaturesImpliedByPlatform();
+ supported_ |= CpuFeaturesImpliedByCompiler();
+
+ if (Serializer::enabled()) {
+ // No probing for features if we might serialize (generate snapshot).
+ return;
+ }
+
// If the compiler is allowed to use fpu then we can use fpu too in our
// code generation.
#if !defined(__mips__)
@@ -62,11 +98,7 @@ void CpuFeatures::Probe() {
supported_ |= 1u << FPU;
}
#else
- if (Serializer::enabled()) {
- supported_ |= OS::CpuFeaturesImpliedByPlatform();
- return; // No features if we might serialize.
- }
-
+ // Probe for additional features not already known to be available.
if (OS::MipsCpuHasFeature(FPU)) {
// This implementation also sets the FPU flags if
// runtime detection of FPU returns true.
@@ -140,7 +172,8 @@ Register ToRegister(int num) {
// -----------------------------------------------------------------------------
// Implementation of RelocInfo.
-const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
+const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
+ 1 << RelocInfo::INTERNAL_REFERENCE;
bool RelocInfo::IsCodedSpecially() {
@@ -514,6 +547,19 @@ bool Assembler::IsJ(Instr instr) {
}
+bool Assembler::IsJal(Instr instr) {
+ return GetOpcodeField(instr) == JAL;
+}
+
+bool Assembler::IsJr(Instr instr) {
+ return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
+}
+
+bool Assembler::IsJalr(Instr instr) {
+ return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
+}
+
+
bool Assembler::IsLui(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
// Checks if the instruction is a load upper immediate.
@@ -907,7 +953,7 @@ void Assembler::GenInstrImmediate(Opcode opcode,
void Assembler::GenInstrJump(Opcode opcode,
- uint32_t address) {
+ uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
ASSERT(is_uint26(address));
Instr instr = opcode | address;
@@ -1080,7 +1126,12 @@ void Assembler::bne(Register rs, Register rt, int16_t offset) {
void Assembler::j(int32_t target) {
- ASSERT(is_uint28(target) && ((target & 3) == 0));
+#if DEBUG
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ ASSERT(in_range && ((target & 3) == 0));
+#endif
GenInstrJump(J, target >> 2);
}
@@ -1096,8 +1147,13 @@ void Assembler::jr(Register rs) {
void Assembler::jal(int32_t target) {
+#ifdef DEBUG
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ ASSERT(in_range && ((target & 3) == 0));
+#endif
positions_recorder()->WriteRecordedPositions();
- ASSERT(is_uint28(target) && ((target & 3) == 0));
GenInstrJump(JAL, target >> 2);
}
@@ -1110,6 +1166,32 @@ void Assembler::jalr(Register rs, Register rd) {
}
+void Assembler::j_or_jr(int32_t target, Register rs) {
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+ if (in_range) {
+ j(target);
+ } else {
+ jr(t9);
+ }
+}
+
+
+void Assembler::jal_or_jalr(int32_t target, Register rs) {
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+ if (in_range) {
+ jal(target);
+ } else {
+ jalr(t9);
+ }
+}
+
+
//-------Data-processing-instructions---------
// Arithmetic.
@@ -1582,6 +1664,13 @@ void Assembler::cfc1(Register rt, FPUControlRegister fs) {
GenInstrRegister(COP1, CFC1, rt, fs);
}
+void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
+ uint64_t i;
+ memcpy(&i, &d, 8);
+
+ *lo = i & 0xffffffff;
+ *hi = i >> 32;
+}
// Arithmetic.
@@ -1940,10 +2029,15 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
}
if (rinfo.rmode() != RelocInfo::NONE) {
// Don't record external references unless the heap will be serialized.
- if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
- !Serializer::enabled() &&
- !FLAG_debug_code) {
- return;
+ if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+#ifdef DEBUG
+ if (!Serializer::enabled()) {
+ Serializer::TooLateToEnableNow();
+ }
+#endif
+ if (!Serializer::enabled() && !emit_debug_code()) {
+ return;
+ }
}
ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
@@ -2038,30 +2132,142 @@ Address Assembler::target_address_at(Address pc) {
}
+// On Mips, a target address is stored in a lui/ori instruction pair, each
+// of which load 16 bits of the 32-bit address to a register.
+// Patching the address must replace both instr, and flush the i-cache.
+//
+// There is an optimization below, which emits a nop when the address
+// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
+// and possibly removed.
void Assembler::set_target_address_at(Address pc, Address target) {
- // On MIPS we patch the address into lui/ori instruction pair.
-
- // First check we have an li (lui/ori pair).
Instr instr2 = instr_at(pc + kInstrSize);
+ uint32_t rt_code = GetRtField(instr2);
+ uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+ uint32_t itarget = reinterpret_cast<uint32_t>(target);
+
#ifdef DEBUG
+ // Check we have the result from a li macro-instruction, using instr pair.
Instr instr1 = instr_at(pc);
-
- // Check we have indeed the result from a li with MustUseReg true.
CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
#endif
- uint32_t rt_code = GetRtField(instr2);
- uint32_t* p = reinterpret_cast<uint32_t*>(pc);
- uint32_t itarget = reinterpret_cast<uint32_t>(target);
-
- // lui rt, high-16.
- // ori rt rt, low-16.
+ // Must use 2 instructions to insure patchable code => just use lui and ori.
+ // lui rt, upper-16.
+ // ori rt rt, lower-16.
*p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
*(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
- CPU::FlushICache(pc, 2 * sizeof(int32_t));
+ // The following code is an optimization for the common case of Call()
+ // or Jump() which is load to register, and jump through register:
+ // li(t9, address); jalr(t9) (or jr(t9)).
+ // If the destination address is in the same 256 MB page as the call, it
+ // is faster to do a direct jal, or j, rather than jump thru register, since
+ // that lets the cpu pipeline prefetch the target address. However each
+ // time the address above is patched, we have to patch the direct jal/j
+ // instruction, as well as possibly revert to jalr/jr if we now cross a
+ // 256 MB page. Note that with the jal/j instructions, we do not need to
+ // load the register, but that code is left, since it makes it easy to
+ // revert this process. A further optimization could try replacing the
+ // li sequence with nops.
+ // This optimization can only be applied if the rt-code from instr2 is the
+ // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
+ // mips return. Occasionally this lands after an li().
+
+ Instr instr3 = instr_at(pc + 2 * kInstrSize);
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
+ bool in_range =
+ ((uint32_t)(ipc ^ itarget) >> (kImm26Bits + kImmFieldShift)) == 0;
+ uint32_t target_field = (uint32_t)(itarget & kJumpAddrMask) >> kImmFieldShift;
+ bool patched_jump = false;
+
+#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
+ // This is a workaround to the 24k core E156 bug (affect some 34k cores also).
+ // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just
+ // apply this workaround for all cores so we don't have to identify the core.
+ if (in_range) {
+ // The 24k core E156 bug has some very specific requirements, we only check
+ // the most simple one: if the address of the delay slot instruction is in
+ // the first or last 32 KB of the 256 MB segment.
+ uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
+ uint32_t ipc_segment_addr = ipc & segment_mask;
+ if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
+ in_range = false;
+ }
+#endif
+
+ if (IsJalr(instr3)) {
+ // Try to convert JALR to JAL.
+ if (in_range && GetRt(instr2) == GetRs(instr3)) {
+ *(p+2) = JAL | target_field;
+ patched_jump = true;
+ }
+ } else if (IsJr(instr3)) {
+ // Try to convert JR to J, skip returns (jr ra).
+ bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
+ if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
+ *(p+2) = J | target_field;
+ patched_jump = true;
+ }
+ } else if (IsJal(instr3)) {
+ if (in_range) {
+ // We are patching an already converted JAL.
+ *(p+2) = JAL | target_field;
+ } else {
+ // Patch JAL, but out of range, revert to JALR.
+ // JALR rs reg is the rt reg specified in the ORI instruction.
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
+ *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+ }
+ patched_jump = true;
+ } else if (IsJ(instr3)) {
+ if (in_range) {
+ // We are patching an already converted J (jump).
+ *(p+2) = J | target_field;
+ } else {
+ // Trying patch J, but out of range, just go back to JR.
+ // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ *(p+2) = SPECIAL | rs_field | JR;
+ }
+ patched_jump = true;
+ }
+
+ CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
}
+void Assembler::JumpLabelToJumpRegister(Address pc) {
+ // Address pc points to lui/ori instructions.
+ // Jump to label may follow at pc + 2 * kInstrSize.
+ uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+#ifdef DEBUG
+ Instr instr1 = instr_at(pc);
+#endif
+ Instr instr2 = instr_at(pc + 1 * kInstrSize);
+ Instr instr3 = instr_at(pc + 2 * kInstrSize);
+ bool patched = false;
+
+ if (IsJal(instr3)) {
+ ASSERT(GetOpcodeField(instr1) == LUI);
+ ASSERT(GetOpcodeField(instr2) == ORI);
+
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
+ *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+ patched = true;
+ } else if (IsJ(instr3)) {
+ ASSERT(GetOpcodeField(instr1) == LUI);
+ ASSERT(GetOpcodeField(instr2) == ORI);
+
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ *(p+2) = SPECIAL | rs_field | JR;
+ patched = true;
+ }
+
+ if (patched) {
+ CPU::FlushICache(pc+2, sizeof(Address));
+ }
+}
} } // namespace v8::internal
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index e5077bee..38e9537a 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -168,24 +168,36 @@ Register ToRegister(int num);
// Coprocessor register.
struct FPURegister {
static const int kNumRegisters = v8::internal::kNumFPURegisters;
- // f0 has been excluded from allocation. This is following ia32
- // where xmm0 is excluded.
- static const int kNumAllocatableRegisters = 15;
+
+ // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
+ // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
+ // number of Double regs (64-bit regs, or FPU-reg-pairs).
+
+ // A few double registers are reserved: one as a scratch register and one to
+ // hold 0.0.
+ // f28: 0.0
+ // f30: scratch register.
+ static const int kNumReservedRegisters = 2;
+ static const int kNumAllocatableRegisters = kNumRegisters / 2 -
+ kNumReservedRegisters;
+
static int ToAllocationIndex(FPURegister reg) {
- ASSERT(reg.code() != 0);
ASSERT(reg.code() % 2 == 0);
- return (reg.code() / 2) - 1;
+ ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
+ ASSERT(reg.is_valid());
+ return (reg.code() / 2);
}
static FPURegister FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
- return from_code((index + 1) * 2);
+ return from_code(index * 2);
}
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
+ "f0",
"f2",
"f4",
"f6",
@@ -198,9 +210,7 @@ struct FPURegister {
"f20",
"f22",
"f24",
- "f26",
- "f28",
- "f30"
+ "f26"
};
return names[index];
}
@@ -212,6 +222,23 @@ struct FPURegister {
bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; }
bool is(FPURegister creg) const { return code_ == creg.code_; }
+ FPURegister low() const {
+ // Find low reg of a Double-reg pair, which is the reg itself.
+ ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
+ FPURegister reg;
+ reg.code_ = code_;
+ ASSERT(reg.is_valid());
+ return reg;
+ }
+ FPURegister high() const {
+ // Find high reg of a Doubel-reg pair, which is reg + 1.
+ ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
+ FPURegister reg;
+ reg.code_ = code_ + 1;
+ ASSERT(reg.is_valid());
+ return reg;
+ }
+
int code() const {
ASSERT(is_valid());
return code_;
@@ -228,9 +255,19 @@ struct FPURegister {
int code_;
};
+// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
+// 32-bit registers, f0 through f31. When used as 'double' they are used
+// in pairs, starting with the even numbered register. So a double operation
+// on f0 really uses f0 and f1.
+// (Modern mips hardware also supports 32 64-bit registers, via setting
+// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
+// but it is not in common use. Someday we will want to support this in v8.)
+
+// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
typedef FPURegister DoubleRegister;
+typedef FPURegister FloatRegister;
-const FPURegister no_creg = { -1 };
+const FPURegister no_freg = { -1 };
const FPURegister f0 = { 0 }; // Return value in hard float mode.
const FPURegister f1 = { 1 };
@@ -265,6 +302,8 @@ const FPURegister f29 = { 29 };
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
+const FPURegister kDoubleRegZero = f28;
+
// FPU (coprocessor 1) control registers.
// Currently only FCSR (#31) is implemented.
struct FPUControlRegister {
@@ -331,6 +370,10 @@ class MemOperand : public Operand {
explicit MemOperand(Register rn, int32_t offset = 0);
int32_t offset() const { return offset_; }
+ bool OffsetIsInt16Encodable() const {
+ return is_int16(offset_);
+ }
+
private:
int32_t offset_;
@@ -504,6 +547,8 @@ class Assembler : public AssemblerBase {
static Address target_address_at(Address pc);
static void set_target_address_at(Address pc, Address target);
+ static void JumpLabelToJumpRegister(Address pc);
+
// This sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code.
inline static void set_target_at(Address instruction_payload,
@@ -534,9 +579,13 @@ class Assembler : public AssemblerBase {
static const int kExternalTargetSize = 0 * kInstrSize;
// Number of consecutive instructions used to store 32bit constant.
- // Used in RelocInfo::target_address_address() function to tell serializer
- // address of the instruction that follows LUI/ORI instruction pair.
- static const int kInstructionsFor32BitConstant = 2;
+ // Before jump-optimizations, this constant was used in
+ // RelocInfo::target_address_address() function to tell serializer address of
+ // the instruction that follows LUI/ORI instruction pair. Now, with new jump
+ // optimization, where jump-through-register instruction that usually
+ // follows LUI/ORI pair is substituted with J/JAL, this constant equals
+ // to 3 instructions (LUI+ORI+J/JAL/JR/JALR).
+ static const int kInstructionsFor32BitConstant = 3;
// Distance between the instruction referring to the address of the call
// target and the return address.
@@ -623,6 +672,8 @@ class Assembler : public AssemblerBase {
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
+ void j_or_jr(int32_t target, Register rs);
+ void jal_or_jalr(int32_t target, Register rs);
//-------Data-processing-instructions---------
@@ -892,6 +943,10 @@ class Assembler : public AssemblerBase {
static bool IsLui(Instr instr);
static bool IsOri(Instr instr);
+ static bool IsJal(Instr instr);
+ static bool IsJr(Instr instr);
+ static bool IsJalr(Instr instr);
+
static bool IsNop(Instr instr, unsigned int type);
static bool IsPop(Instr instr);
static bool IsPush(Instr instr);
@@ -976,6 +1031,8 @@ class Assembler : public AssemblerBase {
return internal_trampoline_exception_;
}
+ void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);
+
bool is_trampoline_emitted() const {
return trampoline_emitted_;
}
@@ -1159,6 +1216,7 @@ class Assembler : public AssemblerBase {
}
return trampoline_slot;
}
+
private:
int start_;
int end_;
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 1555653f..d7723044 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -210,7 +210,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements.
__ bind(&not_empty);
- ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ li(elements_array_end,
(JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize);
__ sra(scratch1, array_size, kSmiTagSize);
@@ -261,7 +261,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Length of the FixedArray is the number of pre-allocated elements if
// the actual JSArray has length 0 and the size of the JSArray for non-empty
// JSArrays. The length of a FixedArray is stored as a smi.
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ li(at, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
__ movz(array_size, at, array_size);
@@ -273,7 +273,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject
// elements_array_storage: elements array element storage
// array_size: smi-tagged size of elements array
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(elements_array_end, array_size, kPointerSizeLog2 - kSmiTagSize);
__ Addu(elements_array_end, elements_array_storage, elements_array_end);
@@ -336,14 +336,14 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ bind(&argc_one_or_more);
__ Branch(&argc_two_or_more, ne, a0, Operand(1));
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ lw(a2, MemOperand(sp)); // Get the argument from the stack.
__ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask));
__ Branch(call_generic_code, eq, a3, Operand(zero_reg));
// Handle construction of an empty array of a certain size. Bail out if size
// is too large to actually allocate an elements array.
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ Branch(call_generic_code, Ugreater_equal, a2,
Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
@@ -576,7 +576,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// Is it a String?
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
- ASSERT(kNotStringTag != 0);
+ STATIC_ASSERT(kNotStringTag != 0);
__ And(t0, a3, Operand(kIsNotStringMask));
__ Branch(&convert_argument, ne, t0, Operand(zero_reg));
__ mov(argument, a0);
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 9385f2fd..521b8e58 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -3538,7 +3538,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
const int kNumInstructionsToJump = 6;
masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame.
- masm->Subu(sp, sp, StandardFrameConstants::kCArgsSlotsSize);
+ masm->Subu(sp, sp, kCArgsSlotsSize);
// Stack is still aligned.
// Call the C routine.
@@ -3551,7 +3551,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
// Restore stack (remove arg slots).
- __ Addu(sp, sp, StandardFrameConstants::kCArgsSlotsSize);
+ __ Addu(sp, sp, kCArgsSlotsSize);
if (always_allocate) {
// It's okay to clobber a2 and a3 here. v0 & v1 contain result.
@@ -3591,7 +3591,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ li(t0,
Operand(ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(a3, MemOperand(t0));
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ lw(v0, MemOperand(t0));
__ sw(a3, MemOperand(t0));
@@ -3695,16 +3695,26 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Save callee saved registers on the stack.
__ MultiPush(kCalleeSaved | ra.bit());
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Save callee-saved FPU registers.
+ __ MultiPushFPU(kCalleeSavedFPU);
+ }
+
// Load argv in s0 register.
- __ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize +
- StandardFrameConstants::kCArgsSlotsSize));
+ int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
+ if (CpuFeatures::IsSupported(FPU)) {
+ offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
+ }
+
+ __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
// We build an EntryFrame.
__ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used.
int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
__ li(t2, Operand(Smi::FromInt(marker)));
__ li(t1, Operand(Smi::FromInt(marker)));
- __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
masm->isolate())));
__ lw(t0, MemOperand(t0));
__ Push(t3, t2, t1, t0);
@@ -3729,7 +3739,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// If this is the outermost JS call, set js_entry_sp value.
Label non_outermost_js;
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
masm->isolate());
__ li(t1, Operand(ExternalReference(js_entry_sp)));
__ lw(t2, MemOperand(t1));
@@ -3752,7 +3762,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// exception field in the JSEnv and return a failure sentinel.
// Coming in here the fp will be invalid because the PushTryHandler below
// sets it to 0 to signal the existence of the JSEntry frame.
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ sw(v0, MemOperand(t0)); // We come back from 'invoke'. result is in v0.
__ li(v0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
@@ -3771,7 +3781,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ li(t0,
Operand(ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(t1, MemOperand(t0));
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ sw(t1, MemOperand(t0));
@@ -3822,13 +3832,19 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Restore the top frame descriptors from the stack.
__ pop(t1);
- __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
masm->isolate())));
__ sw(t1, MemOperand(t0));
// Reset the stack to the callee saved registers.
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Restore callee-saved fpu registers.
+ __ MultiPopFPU(kCalleeSavedFPU);
+ }
+
// Restore callee saved registers from the stack.
__ MultiPop(kCalleeSaved | ra.bit());
// Return.
@@ -4652,7 +4668,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// frame. Therefore we have to use fp, which points exactly to two pointer
// sizes below the previous sp. (Because creating a new stack frame pushes
// the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
- __ lw(a0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+ __ lw(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
// If slice offset is not 0, load the length from the original sliced string.
// Argument 4, a3: End of string data
// Argument 3, a2: Start of string data
@@ -4662,7 +4678,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ sllv(t1, a1, a3);
__ addu(a2, t0, t1);
- __ lw(t2, FieldMemOperand(a0, String::kLengthOffset));
+ __ lw(t2, FieldMemOperand(subject, String::kLengthOffset));
__ sra(t2, t2, kSmiTagSize);
__ sllv(t1, t2, a3);
__ addu(a3, t0, t1);
@@ -4670,7 +4686,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Already there
// Argument 1 (a0): Subject string.
- // Already there
+ __ mov(a0, subject);
// Locate the code entry and call it.
__ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4688,13 +4704,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
Label success;
__ Branch(&success, eq,
- subject, Operand(NativeRegExpMacroAssembler::SUCCESS));
+ v0, Operand(NativeRegExpMacroAssembler::SUCCESS));
Label failure;
__ Branch(&failure, eq,
- subject, Operand(NativeRegExpMacroAssembler::FAILURE));
+ v0, Operand(NativeRegExpMacroAssembler::FAILURE));
// If not exception it can only be retry. Handle that in the runtime system.
__ Branch(&runtime, ne,
- subject, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+ v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// Result must now be exception. If there is no pending exception already a
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
@@ -4702,19 +4718,19 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ li(a1, Operand(
ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(a1, MemOperand(a1, 0));
- __ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ lw(v0, MemOperand(a2, 0));
- __ Branch(&runtime, eq, subject, Operand(a1));
+ __ Branch(&runtime, eq, v0, Operand(a1));
__ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception;
- __ Branch(&termination_exception, eq, subject, Operand(a0));
+ __ Branch(&termination_exception, eq, v0, Operand(a0));
- __ Throw(subject); // Expects thrown value in v0.
+ __ Throw(v0); // Expects thrown value in v0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0.
@@ -5062,7 +5078,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ And(t0, result_, Operand(kStringEncodingMask));
__ Branch(&ascii_string, ne, t0, Operand(zero_reg));
@@ -5625,11 +5642,6 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Register to = t2;
Register from = t3;
- if (FLAG_string_slices) {
- __ nop(); // Jumping as first instruction would crash the code generation.
- __ jmp(&sub_string_runtime);
- }
-
// Check bounds and smi-ness.
__ lw(to, MemOperand(sp, kToOffset));
__ lw(from, MemOperand(sp, kFromOffset));
@@ -5653,7 +5665,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Special handling of sub-strings of length 1 and 2. One character strings
// are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache.
+ // cache). Two character strings are looked for in the symbol cache in
+ // generated code.
__ Branch(&sub_string_runtime, lt, a2, Operand(2));
// Both to and from are smis.
@@ -5665,19 +5678,32 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// t5: to index (untagged smi)
// Make sure first argument is a sequential (or flat) string.
- __ lw(t1, MemOperand(sp, kStringOffset));
- __ Branch(&sub_string_runtime, eq, t1, Operand(kSmiTagMask));
+ __ lw(v0, MemOperand(sp, kStringOffset));
+ __ Branch(&sub_string_runtime, eq, v0, Operand(kSmiTagMask));
- __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
- __ And(t4, a1, Operand(kIsNotStringMask));
+ __ And(t4, v0, Operand(kIsNotStringMask));
__ Branch(&sub_string_runtime, ne, t4, Operand(zero_reg));
+ // Short-cut for the case of trivial substring.
+ Label return_v0;
+ // v0: original string
+ // a2: result string length
+ __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
+ __ sra(t0, t0, 1);
+ __ Branch(&return_v0, eq, a2, Operand(t0));
+
+ Label create_slice;
+ if (FLAG_string_slices) {
+ __ Branch(&create_slice, ge, a2, Operand(SlicedString::kMinLength));
+ }
+
+ // v0: original string
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
@@ -5686,8 +5712,9 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ And(t0, a1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
- // External strings go to runtime.
+ // Slices and external strings go to runtime.
__ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag));
// Sequential strings are handled directly.
@@ -5696,32 +5723,32 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened
// cons strings, but not much).
- __ lw(t1, FieldMemOperand(t1, ConsString::kFirstOffset));
- __ lw(t0, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset));
+ __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset));
STATIC_ASSERT(kSeqStringTag == 0);
- // Cons and External strings go to runtime.
+ // Cons, slices and external strings go to runtime.
__ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask));
// Definitly a sequential string.
__ bind(&seq_string);
+ // v0: original string
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
- __ lw(t0, FieldMemOperand(t1, String::kLengthOffset));
+ __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
__ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length.
to = no_reg;
+ // v0: original string or left hand side of the original cons string.
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
@@ -5737,84 +5764,147 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Sub string of length 2 requested.
// Get the two characters forming the sub string.
- __ Addu(t1, t1, Operand(a3));
- __ lbu(a3, FieldMemOperand(t1, SeqAsciiString::kHeaderSize));
- __ lbu(t0, FieldMemOperand(t1, SeqAsciiString::kHeaderSize + 1));
+ __ Addu(v0, v0, Operand(a3));
+ __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
+ __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table.
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
-
+ __ jmp(&return_v0);
// a2: result string length.
// a3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string);
__ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime);
__ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_v0);
__ bind(&result_longer_than_two);
+ // Locate 'from' character of string.
+ __ Addu(t1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ __ sra(t4, from, 1);
+ __ Addu(t1, t1, t4);
+
// Allocate the result.
__ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime);
- // v0: result string.
- // a2: result string length.
+ // v0: result string
+ // a2: result string length
// a3: from index (untagged smi)
- // t1: string.
+ // t1: first character of substring to copy
// t3: (a.k.a. from): from offset (smi)
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- __ Addu(t1, t1, Operand(a3));
- // v0: result string.
- // a1: first character of result string.
- // a2: result string length.
- // t1: first character of sub string to copy.
+ // v0: result string
+ // a1: first character of result string
+ // a2: result string length
+ // t1: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_v0);
__ bind(&non_ascii_flat);
- // a2: result string length.
- // t1: string.
+ // a2: result string length
+ // t1: string
// t3: (a.k.a. from): from offset (smi)
// Check for flat two byte string.
+ // Locate 'from' character of string.
+ __ Addu(t1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ // As "from" is a smi it is 2 times the value which matches the size of a two
+ // byte character.
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ Addu(t1, t1, Operand(from));
+
// Allocate the result.
__ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime);
- // v0: result string.
- // a2: result string length.
- // t1: string.
+ // v0: result string
+ // a2: result string length
+ // t1: first character of substring to copy
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ Addu(t1, t1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // As "from" is a smi it is 2 times the value which matches the size of a two
- // byte character.
- __ Addu(t1, t1, Operand(from));
+
from = no_reg;
// v0: result string.
// a1: first character of result.
// a2: result length.
- // t1: first character of string to copy.
+ // t1: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED);
+ __ jmp(&return_v0);
+
+ if (FLAG_string_slices) {
+ __ bind(&create_slice);
+ // v0: original string
+ // a1: instance type
+ // a2: length
+ // a3: from index (untagged smi)
+ // t2 (a.k.a. to): to (smi)
+ // t3 (a.k.a. from): from offset (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ And(t4, a1, Operand(kStringRepresentationMask));
+ __ Branch(&seq_string, eq, t4, Operand(zero_reg));
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ And(t4, a1, Operand(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ Branch(&sub_string_runtime, eq, t4, Operand(zero_reg));
+
+ __ And(t4, a1, Operand(kSlicedNotConsMask));
+ __ Branch(&sliced_string, ne, t4, Operand(zero_reg));
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
+ __ LoadRoot(t5, Heap::kEmptyStringRootIndex);
+ __ Branch(&sub_string_runtime, ne, t1, Operand(t5));
+ __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ addu(t3, t3, t1);
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ mov(t1, v0);
+
+ __ bind(&allocate_slice);
+ // a1: instance type of original string
+ // a2: length
+ // t1: underlying subject string
+ // t3 (a.k.a. from): from offset (smi)
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ And(t4, a1, Operand(kStringEncodingMask));
+ __ Branch(&two_byte_slice, eq, t4, Operand(zero_reg));
+ __ AllocateAsciiSlicedString(v0, a2, a3, t0, &sub_string_runtime);
+ __ jmp(&set_slice_header);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(v0, a2, a3, t0, &sub_string_runtime);
+ __ bind(&set_slice_header);
+ __ sw(t3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ }
+
+ __ bind(&return_v0);
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
__ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret();
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index 96a23338..d0a7af5c 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -191,6 +191,7 @@ bool Instruction::IsLinkingInstruction() const {
const int op = OpcodeFieldRaw();
switch (op) {
case JAL:
+ return true;
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
@@ -272,7 +273,7 @@ Instruction::Type Instruction::InstructionType() const {
case MOVCI:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case SPECIAL2:
@@ -281,7 +282,7 @@ Instruction::Type Instruction::InstructionType() const {
case CLZ:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case SPECIAL3:
@@ -290,7 +291,7 @@ Instruction::Type Instruction::InstructionType() const {
case EXT:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case COP1: // Coprocessor instructions.
@@ -341,7 +342,7 @@ Instruction::Type Instruction::InstructionType() const {
case JAL:
return kJumpType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
return kUnsupported;
}
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 6bf2570e..d76ae59f 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -204,6 +204,10 @@ static const int kImm26Bits = 26;
static const int kImm28Shift = 0;
static const int kImm28Bits = 28;
+// In branches and jumps immediate fields point to words, not bytes,
+// and are therefore shifted by 2.
+static const int kImmFieldShift = 2;
+
static const int kFsShift = 11;
static const int kFsBits = 5;
static const int kFtShift = 16;
@@ -233,7 +237,7 @@ static const int kFunctionFieldMask =
static const int kHiMask = 0xffff << 16;
static const int kLoMask = 0xffff;
static const int kSignMask = 0x80000000;
-
+static const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;
// ----- MIPS Opcodes and Function Fields.
// We use this presentation to stay close to the table representation in
@@ -290,12 +294,12 @@ enum Opcode {
enum SecondaryField {
// SPECIAL Encoding of Function Field.
SLL = ((0 << 3) + 0),
+ MOVCI = ((0 << 3) + 1),
SRL = ((0 << 3) + 2),
SRA = ((0 << 3) + 3),
SLLV = ((0 << 3) + 4),
SRLV = ((0 << 3) + 6),
SRAV = ((0 << 3) + 7),
- MOVCI = ((0 << 3) + 1),
JR = ((1 << 3) + 0),
JALR = ((1 << 3) + 1),
@@ -498,14 +502,38 @@ inline Condition ReverseCondition(Condition cc) {
// ----- Coprocessor conditions.
enum FPUCondition {
- F, // False.
- UN, // Unordered.
- EQ, // Equal.
- UEQ, // Unordered or Equal.
- OLT, // Ordered or Less Than.
- ULT, // Unordered or Less Than.
- OLE, // Ordered or Less Than or Equal.
- ULE // Unordered or Less Than or Equal.
+ kNoFPUCondition = -1,
+
+ F = 0, // False.
+ UN = 1, // Unordered.
+ EQ = 2, // Equal.
+ UEQ = 3, // Unordered or Equal.
+ OLT = 4, // Ordered or Less Than.
+ ULT = 5, // Unordered or Less Than.
+ OLE = 6, // Ordered or Less Than or Equal.
+ ULE = 7 // Unordered or Less Than or Equal.
+};
+
+
+// FPU rounding modes.
+enum FPURoundingMode {
+ RN = 0 << 0, // Round to Nearest.
+ RZ = 1 << 0, // Round towards zero.
+ RP = 2 << 0, // Round towards Plus Infinity.
+ RM = 3 << 0, // Round towards Minus Infinity.
+
+ // Aliases.
+ kRoundToNearest = RN,
+ kRoundToZero = RZ,
+ kRoundToPlusInf = RP,
+ kRoundToMinusInf = RM
+};
+
+static const uint32_t kFPURoundingModeMask = 3 << 0;
+
+enum CheckForInexactConversion {
+ kCheckForInexactConversion,
+ kDontCheckForInexactConversion
};
@@ -716,7 +744,7 @@ class Instruction {
inline int32_t Imm26Value() const {
ASSERT(InstructionType() == kJumpType);
- return Bits(kImm16Shift + kImm26Bits - 1, kImm26Shift);
+ return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}
// Say if the instruction should not be used in a branch delay slot.
@@ -743,11 +771,9 @@ class Instruction {
// -----------------------------------------------------------------------------
// MIPS assembly various constants.
-
-static const int kArgsSlotsSize = 4 * Instruction::kInstrSize;
-static const int kArgsSlotsNum = 4;
// C/C++ argument slots size.
-static const int kCArgsSlotsSize = 4 * Instruction::kInstrSize;
+static const int kCArgSlotCount = 4;
+static const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize;
// JS argument slots size.
static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize;
// Assembly builtins argument slots size.
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 7df5c417..fde0c58f 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -112,7 +112,7 @@ class Decoder {
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
- void PrintImm26(Instruction* instr);
+ void PrintXImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
@@ -273,9 +273,9 @@ void Decoder::PrintXImm16(Instruction* instr) {
// Print 26-bit immediate value.
-void Decoder::PrintImm26(Instruction* instr) {
- int32_t imm = instr->Imm26Value();
- out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
+void Decoder::PrintXImm26(Instruction* instr) {
+ uint32_t imm = instr->Imm26Value() << kImmFieldShift;
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
@@ -383,9 +383,9 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
}
return 6;
} else {
- ASSERT(STRING_STARTS_WITH(format, "imm26"));
- PrintImm26(instr);
- return 5;
+ ASSERT(STRING_STARTS_WITH(format, "imm26x"));
+ PrintXImm26(instr);
+ return 6;
}
}
case 'r': { // 'r: registers.
@@ -926,10 +926,10 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
void Decoder::DecodeTypeJump(Instruction* instr) {
switch (instr->OpcodeFieldRaw()) {
case J:
- Format(instr, "j 'imm26");
+ Format(instr, "j 'imm26x");
break;
case JAL:
- Format(instr, "jal 'imm26");
+ Format(instr, "jal 'imm26x");
break;
default:
UNREACHABLE();
@@ -958,6 +958,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
break;
}
default: {
+ Format(instr, "UNSUPPORTED");
UNSUPPORTED_MIPS();
}
}
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 1899843a..2c838938 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -30,7 +30,6 @@
#ifndef V8_MIPS_FRAMES_MIPS_H_
#define V8_MIPS_FRAMES_MIPS_H_
-
namespace v8 {
namespace internal {
@@ -40,13 +39,22 @@ namespace internal {
static const int kNumRegs = 32;
static const RegList kJSCallerSaved =
- 1 << 2 | // v0
- 1 << 4 | // a0
- 1 << 5 | // a1
- 1 << 6 | // a2
- 1 << 7; // a3
-
-static const int kNumJSCallerSaved = 5;
+ 1 << 2 | // v0
+ 1 << 3 | // v1
+ 1 << 4 | // a0
+ 1 << 5 | // a1
+ 1 << 6 | // a2
+ 1 << 7 | // a3
+ 1 << 8 | // t0
+ 1 << 9 | // t1
+ 1 << 10 | // t2
+ 1 << 11 | // t3
+ 1 << 12 | // t4
+ 1 << 13 | // t5
+ 1 << 14 | // t6
+ 1 << 15; // t7
+
+static const int kNumJSCallerSaved = 14;
// Return the code of the n-th caller-saved register available to JavaScript
@@ -56,19 +64,30 @@ int JSCallerSavedCode(int n);
// Callee-saved registers preserved when switching from C to JavaScript.
static const RegList kCalleeSaved =
- // Saved temporaries.
- 1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 |
- 1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 |
- // fp.
- 1 << 30;
+ 1 << 16 | // s0
+ 1 << 17 | // s1
+ 1 << 18 | // s2
+ 1 << 19 | // s3
+ 1 << 20 | // s4
+ 1 << 21 | // s5
+ 1 << 22 | // s6 (roots in Javascript code)
+ 1 << 23 | // s7 (cp in Javascript code)
+ 1 << 30; // fp/s8
static const int kNumCalleeSaved = 9;
+static const RegList kCalleeSavedFPU =
+ 1 << 20 | // f20
+ 1 << 22 | // f22
+ 1 << 24 | // f24
+ 1 << 26 | // f26
+ 1 << 28 | // f28
+ 1 << 30; // f30
+static const int kNumCalleeSavedFPU = 6;
// Number of registers for which space is reserved in safepoints. Must be a
// multiple of 8.
-// TODO(mips): Only 8 registers may actually be sufficient. Revisit.
-static const int kNumSafepointRegisters = 16;
+static const int kNumSafepointRegisters = 24;
// Define the list of registers actually saved at safepoints.
// Note that the number of saved registers may be smaller than the reserved
@@ -82,37 +101,37 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
static const int kUndefIndex = -1;
// Map with indexes on stack that corresponds to codes of saved registers.
static const int kSafepointRegisterStackIndexMap[kNumRegs] = {
- kUndefIndex,
- kUndefIndex,
- 0, // v0
- kUndefIndex,
- 1, // a0
- 2, // a1
- 3, // a2
- 4, // a3
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- 5, // Saved temporaries.
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- 13, // gp
- 14, // sp
- 15, // fp
+ kUndefIndex, // zero_reg
+ kUndefIndex, // at
+ 0, // v0
+ 1, // v1
+ 2, // a0
+ 3, // a1
+ 4, // a2
+ 5, // a3
+ 6, // t0
+ 7, // t1
+ 8, // t2
+ 9, // t3
+ 10, // t4
+ 11, // t5
+ 12, // t6
+ 13, // t7
+ 14, // s0
+ 15, // s1
+ 16, // s2
+ 17, // s3
+ 18, // s4
+ 19, // s5
+ 20, // s6
+ 21, // s7
+ kUndefIndex, // t8
+ kUndefIndex, // t9
+ kUndefIndex, // k0
+ kUndefIndex, // k1
+ kUndefIndex, // gp
+ kUndefIndex, // sp
+ 22, // fp
kUndefIndex
};
@@ -174,9 +193,6 @@ class StandardFrameConstants : public AllStatic {
static const int kRArgsSlotsSize = 4 * kPointerSize;
static const int kRegularArgsSlotsSize = kRArgsSlotsSize;
- // C/C++ argument slots size.
- static const int kCArgSlotCount = 4;
- static const int kCArgsSlotsSize = kCArgSlotCount * kPointerSize;
// JS argument slots size.
static const int kJSArgsSlotsSize = 0 * kPointerSize;
// Assembly builtins argument slots size.
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index d3f89228..9a210c49 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -200,14 +200,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ lw(a0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ li(a1, Operand(Context::SlotOffset(slot->index())));
+ __ li(a1, Operand(Context::SlotOffset(var->index())));
__ addu(a2, cp, a1);
__ sw(a0, MemOperand(a2, 0));
// Update the write barrier. This clobbers all involved
@@ -252,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), v0, a1, a2);
+ SetVar(arguments, v0, a1, a2);
}
if (FLAG_trace) {
@@ -266,17 +266,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ LoadRoot(t0, Heap::kStackLimitRootIndex);
__ Branch(&ok, hs, sp, Operand(t0));
@@ -370,24 +372,27 @@ void FullCodeGenerator::EmitReturnSequence() {
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
__ push(result_register());
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -620,29 +625,56 @@ void FullCodeGenerator::Split(Condition cc,
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return MemOperand(fp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
+ }
+ return MemOperand(fp, offset);
+}
+
+
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
}
- UNREACHABLE();
- return MemOperand(v0, 0);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
// Use destination as scratch.
- MemOperand slot_operand = EmitSlotSearch(source, destination);
- __ lw(destination, slot_operand);
+ MemOperand location = VarOperand(var, dest);
+ __ lw(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
+ __ sw(src, location);
+ // Emit the write barrier code if the location is in the heap.
+ if (var->IsContextSlot()) {
+ __ RecordWrite(scratch0,
+ Operand(Context::SlotOffset(var->index())),
+ scratch1,
+ src);
+ }
}
@@ -672,47 +704,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
- __ sw(src, location);
- // Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- __ RecordWrite(scratch1,
- Operand(Context::SlotOffset(dst->index())),
- scratch2,
- src);
- }
-}
-
-
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- if (mode == Variable::CONST) {
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ sw(t0, MemOperand(fp, SlotOffset(slot)));
- } else if (function != NULL) {
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
+ __ sw(result_register(), StackOperand(variable));
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ sw(t0, StackOperand(variable));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -726,23 +744,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ Check(ne, "Declaration in catch context.",
a1, Operand(t0));
}
- if (mode == Variable::CONST) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ sw(at, ContextOperand(cp, slot->index()));
- // No write barrier since the_hole_value is in old space.
- } else if (function != NULL) {
+ if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ sw(result_register(), ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
+ __ sw(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
// We know that we have written a function, which is not a smi.
__ mov(a1, cp);
__ RecordWrite(a1, Operand(offset), a2, result_register());
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ sw(at, ContextOperand(cp, variable->index()));
+ // No write barrier since the_hole_value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ li(a2, Operand(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -752,17 +775,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (mode == Variable::CONST) {
- __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
- __ Push(cp, a2, a1, a0);
- } else if (function != NULL) {
+ if (function != NULL) {
__ Push(cp, a2, a1);
// Push initial value for function declaration.
VisitForStackValue(function);
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
+ __ Push(cp, a2, a1, a0);
} else {
ASSERT(Smi::FromInt(0) == 0);
- // No initial value!
- __ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
+ __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
__ Push(cp, a2, a1, a0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -772,19 +794,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
- __ li(a2, Operand(pairs));
- __ li(a1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, a2, a1, a0);
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ li(a1, Operand(pairs));
+ __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
+ __ Push(cp, a1, a0);
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1088,10 +1107,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register current = cp;
Register next = a1;
Register temp = a2;
@@ -1135,7 +1153,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
__ lw(a0, GlobalObjectOperand());
- __ li(a2, Operand(slot->var()->name()));
+ __ li(a2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1144,15 +1162,14 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = cp;
Register next = a3;
Register temp = t0;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1171,60 +1188,32 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to
// return an cp-based operand (the write barrier cannot be allowed to
// destroy the cp register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ Branch(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ lw(v0, ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
- __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
- __ movz(v0, a0, at); // Conditional move.
- }
- __ Branch(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ lw(a1,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ li(a0, Operand(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ Branch(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
+ __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
}
+ __ Branch(done);
}
}
@@ -1234,54 +1223,63 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in a2 and the global
- // object (receiver) in a0.
- __ lw(a0, GlobalObjectOperand());
- __ li(a2, Operand(var->name()));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(v0);
-
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ li(a1, Operand(var->name()));
- __ Push(cp, a1); // Context and name.
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in a2 and the global
+ // object (receiver) in a0.
+ __ lw(a0, GlobalObjectOperand());
+ __ li(a2, Operand(var->name()));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(v0);
+ break;
+ }
- context()->Plug(v0);
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ GetVar(v0, var);
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
+ if (var->mode() == Variable::LET) {
+ Label done;
+ __ Branch(&done, ne, at, Operand(zero_reg));
+ __ li(a0, Operand(var->name()));
+ __ push(a0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&done);
+ } else {
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
+ __ movz(v0, a0, at); // Conditional move: Undefined if TheHole.
+ }
+ context()->Plug(v0);
+ }
+ break;
+ }
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- MemOperand slot_operand = EmitSlotSearch(slot, a0);
- __ lw(v0, slot_operand);
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
- __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
- __ movz(v0, a0, at); // Conditional move.
- context()->Plug(v0);
- } else {
- context()->Plug(slot);
- }
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ li(a1, Operand(var->name()));
+ __ Push(cp, a1); // Context and name.
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
+ __ bind(&done);
+ context()->Plug(v0);
+ }
}
}
@@ -1819,14 +1817,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in a0, variable name in
- // a2, and the global object in a1.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(a0, result_register());
__ li(a2, Operand(var->name()));
__ lw(a1, GlobalObjectOperand());
@@ -1836,66 +1828,83 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- // Detect const reinitialization by checking for the hole value.
- __ lw(a1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ Branch(&skip, ne, a1, Operand(t0));
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(result_register());
- __ li(a0, Operand(slot->var()->name()));
- __ Push(cp, a0); // Context and name.
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ lw(a1, StackOperand(var));
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Branch(&skip, ne, a1, Operand(t0));
+ __ sw(result_register(), StackOperand(var));
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(v0);
+ __ li(a0, Operand(var->name()));
+ __ Push(cp, a0); // Context and name.
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
-
- } else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, a1);
- // Perform the assignment and issue the write barrier.
- __ sw(result_register(), target);
+ } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(v0); // Value.
+ __ li(a1, Operand(var->name()));
+ __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, a1, a0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, a1);
+ __ lw(a3, location);
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Branch(&assign, ne, a3, Operand(t0));
+ __ li(a3, Operand(var->name()));
+ __ push(a3);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ bind(&assign);
+ __ sw(result_register(), location);
+ if (var->IsContextSlot()) {
// RecordWrite may destroy all its register arguments.
__ mov(a3, result_register());
- int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+ int offset = Context::SlotOffset(var->index());
__ RecordWrite(a1, Operand(offset), a2, a3);
- break;
}
+ }
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(v0); // Value.
- __ li(a1, Operand(slot->var()->name()));
- __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, a1, a0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ } else if (var->mode() != Variable::CONST) {
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, a1);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ lw(a2, location);
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Check(eq, "Let binding re-initialization.", a2, Operand(t0));
+ }
+ // Perform the assignment.
+ __ sw(v0, location);
+ if (var->IsContextSlot()) {
+ __ mov(a3, v0);
+ __ RecordWrite(a1, Operand(Context::SlotOffset(var->index())), a2, a3);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(v0); // Value.
+ __ li(a1, Operand(var->name()));
+ __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, a1, a0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2033,9 +2042,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2066,9 +2074,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
__ Call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2089,8 +2096,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2113,8 +2119,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
int receiver_offset = 2 + info_->scope()->num_parameters();
__ lw(a1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(a1);
- // Push the strict mode flag.
- __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ li(a1, Operand(Smi::FromInt(strict_mode)));
__ push(a1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@@ -2131,10 +2142,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
@@ -2143,7 +2155,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
@@ -2151,16 +2163,16 @@ void FullCodeGenerator::VisitCall(Call* expr) {
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
+
// If we know that eval can only be shadowed by eval-introduced
// variables we attempt to load the global eval function directly
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(v0);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2168,14 +2180,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(a1);
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in v0 (function) and
// v1 (receiver). Touch up the stack with the right values.
@@ -2184,37 +2194,32 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ lw(a0, GlobalObjectOperand());
__ push(a0);
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
__ push(context_register());
- __ li(a2, Operand(var->name()));
+ __ li(a2, Operand(proxy->name()));
__ push(a2);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ Push(v0, v1); // Function, receiver.
@@ -2239,26 +2244,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ lw(a1, GlobalObjectOperand());
@@ -3206,7 +3206,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
Label done, not_found;
- ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// a2 now holds finger offset as a smi.
__ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -3570,9 +3570,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
__ li(a2, Operand(expr->name()));
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count,
- NOT_IN_LOOP,
- mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3588,32 +3586,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
__ push(a1);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ lw(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
__ li(a0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(a2, a1, a0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
// Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects.
- context()->Plug(false);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3888,8 +3886,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
+ ASSERT(!context()->IsEffect());
+ ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(proxy->name()));
@@ -3899,15 +3899,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ Call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(v0);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ li(a0, Operand(proxy->name()));
@@ -4198,7 +4195,7 @@ void FullCodeGenerator::EnterFinallyBlock() {
// Cook return address in link register to stack (smi encoded Code* delta).
__ Subu(a1, ra, Operand(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
- ASSERT_EQ(0, kSmiTag);
+ STATIC_ASSERT(0 == kSmiTag);
__ Addu(a1, a1, Operand(a1)); // Convert to smi.
__ push(a1);
}
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 85cb9164..a76c215a 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -146,7 +146,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at,
scratch1,
- Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
@@ -196,9 +196,9 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
const int kElementsStartOffset = StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
__ Branch(miss, ne, at, Operand(zero_reg));
@@ -338,7 +338,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
__ Addu(scratch1, elements,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// The key is a smi.
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
__ addu(at, at, scratch1);
__ lw(scratch2, MemOperand(at));
@@ -372,7 +372,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
// Is the string a symbol?
// map: key map
__ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
- ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kSymbolTag != 0);
__ And(at, hash, Operand(kIsSymbolMask));
__ Branch(not_symbol, eq, at, Operand(zero_reg));
}
@@ -395,7 +395,6 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -732,9 +731,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, a0, a2, a3, t0, t1);
@@ -1269,7 +1266,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ Branch(&slow, hs, key, Operand(t0));
// Calculate key + 1 as smi.
- ASSERT_EQ(0, kSmiTag);
+ STATIC_ASSERT(0 == kSmiTag);
__ Addu(t3, key, Operand(Smi::FromInt(1)));
__ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ Branch(&fast);
@@ -1395,10 +1392,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, a1, a2, a3, t0, t1);
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index c7f727be..4c48ef18 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -441,7 +441,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
- And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
+ And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
@@ -703,52 +703,114 @@ void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
void MacroAssembler::MultiPush(RegList regs) {
- int16_t NumSaved = 0;
- int16_t NumToPush = NumberOfBitsSet(regs);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kPointerSize;
- addiu(sp, sp, -4 * NumToPush);
+ Subu(sp, sp, Operand(stack_offset));
for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) {
- sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
+ stack_offset -= kPointerSize;
+ sw(ToRegister(i), MemOperand(sp, stack_offset));
}
}
}
void MacroAssembler::MultiPushReversed(RegList regs) {
- int16_t NumSaved = 0;
- int16_t NumToPush = NumberOfBitsSet(regs);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kPointerSize;
- addiu(sp, sp, -4 * NumToPush);
+ Subu(sp, sp, Operand(stack_offset));
for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) {
- sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
+ stack_offset -= kPointerSize;
+ sw(ToRegister(i), MemOperand(sp, stack_offset));
}
}
}
void MacroAssembler::MultiPop(RegList regs) {
- int16_t NumSaved = 0;
+ int16_t stack_offset = 0;
for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) {
- lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
+ lw(ToRegister(i), MemOperand(sp, stack_offset));
+ stack_offset += kPointerSize;
}
}
- addiu(sp, sp, 4 * NumSaved);
+ addiu(sp, sp, stack_offset);
}
void MacroAssembler::MultiPopReversed(RegList regs) {
- int16_t NumSaved = 0;
+ int16_t stack_offset = 0;
for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) {
- lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
+ lw(ToRegister(i), MemOperand(sp, stack_offset));
+ stack_offset += kPointerSize;
}
}
- addiu(sp, sp, 4 * NumSaved);
+ addiu(sp, sp, stack_offset);
+}
+
+
+void MacroAssembler::MultiPushFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kDoubleSize;
+
+ Subu(sp, sp, Operand(stack_offset));
+ for (int16_t i = kNumRegisters; i > 0; i--) {
+ if ((regs & (1 << i)) != 0) {
+ stack_offset -= kDoubleSize;
+ sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ }
+ }
+}
+
+
+void MacroAssembler::MultiPushReversedFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kDoubleSize;
+
+ Subu(sp, sp, Operand(stack_offset));
+ for (int16_t i = 0; i < kNumRegisters; i++) {
+ if ((regs & (1 << i)) != 0) {
+ stack_offset -= kDoubleSize;
+ sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ }
+ }
+}
+
+
+void MacroAssembler::MultiPopFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t stack_offset = 0;
+
+ for (int16_t i = 0; i < kNumRegisters; i++) {
+ if ((regs & (1 << i)) != 0) {
+ ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ stack_offset += kDoubleSize;
+ }
+ }
+ addiu(sp, sp, stack_offset);
+}
+
+
+void MacroAssembler::MultiPopReversedFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t stack_offset = 0;
+
+ for (int16_t i = kNumRegisters; i > 0; i--) {
+ if ((regs & (1 << i)) != 0) {
+ ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ stack_offset += kDoubleSize;
+ }
+ }
+ addiu(sp, sp, stack_offset);
}
@@ -2275,7 +2337,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
li(t0, Operand(StackHandler::TRY_FINALLY));
}
// Save the current handler as the next handler.
- li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
@@ -2297,7 +2359,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
li(t0, Operand(StackHandler::ENTRY));
// Save the current handler as the next handler.
- li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(t1, MemOperand(t2));
ASSERT(Smi::FromInt(0) == 0); // Used for no context.
@@ -2319,7 +2381,7 @@ void MacroAssembler::PopTryHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
- li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
sw(a1, MemOperand(at));
}
@@ -2337,7 +2399,7 @@ void MacroAssembler::Throw(Register value) {
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Drop the sp to the top of the handler.
- li(a3, Operand(ExternalReference(Isolate::k_handler_address,
+ li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
isolate())));
lw(sp, MemOperand(a3));
@@ -2400,7 +2462,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Move(v0, value);
// Drop sp to the top stack handler.
- li(a3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(sp, MemOperand(a3));
// Unwind the handlers until the ENTRY handler is found.
@@ -2423,7 +2485,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
li(a0, Operand(false, RelocInfo::NONE));
li(a2, Operand(external_caught));
sw(a0, MemOperand(a2));
@@ -2431,7 +2493,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Set pending exception and v0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate())));
sw(v0, MemOperand(a2));
}
@@ -2753,6 +2815,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
// Allocates a heap number or jumps to the label if the young space is full and
// a scavenge is needed.
void MacroAssembler::AllocateHeapNumber(Register result,
@@ -2873,7 +2975,7 @@ void MacroAssembler::CopyBytes(Register src,
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue));
}
@@ -3871,9 +3973,9 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
sw(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
- li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
sw(fp, MemOperand(t8));
- li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
sw(cp, MemOperand(t8));
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
@@ -3923,11 +4025,11 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
}
// Clear top frame.
- li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
sw(zero_reg, MemOperand(t8));
// Restore current context from top and clear it in debug mode.
- li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
lw(cp, MemOperand(t8));
#ifdef DEBUG
sw(a3, MemOperand(t8));
@@ -4151,11 +4253,9 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
// mips, even though those argument slots are not normally used.
// Remaining arguments are pushed on the stack, above (higher address than)
// the argument slots.
- ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) +
- (StandardFrameConstants::kCArgsSlotsSize /
- kPointerSize);
+ kCArgSlotCount;
if (frame_alignment > kPointerSize) {
// Make stack end at alignment and make room for num_arguments - 4 words
// and the original value of sp.
@@ -4227,11 +4327,9 @@ void MacroAssembler::CallCFunctionHelper(Register function,
Call(function);
- ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) +
- (StandardFrameConstants::kCArgsSlotsSize /
- kPointerSize);
+ kCArgSlotCount;
if (OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 0fcf6f1d..5dd012e9 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -362,6 +362,16 @@ class MacroAssembler: public Assembler {
Register scratch1,
Register scratch2,
Label* gc_required);
+ void AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
// Allocates a heap number or jumps to the gc_required label if the young
// space is full and a scavenge is needed. All registers are clobbered also
@@ -442,6 +452,9 @@ class MacroAssembler: public Assembler {
void MultiPush(RegList regs);
void MultiPushReversed(RegList regs);
+ void MultiPushFPU(RegList regs);
+ void MultiPushReversedFPU(RegList regs);
+
// Lower case push() for compatibility with arch-independent code.
void push(Register src) {
Addu(sp, sp, Operand(-kPointerSize));
@@ -487,6 +500,9 @@ class MacroAssembler: public Assembler {
void MultiPop(RegList regs);
void MultiPopReversed(RegList regs);
+ void MultiPopFPU(RegList regs);
+ void MultiPopReversedFPU(RegList regs);
+
// Lower case pop() for compatibility with arch-independent code.
void pop(Register dst) {
lw(dst, MemOperand(sp, 0));
@@ -1197,10 +1213,9 @@ static inline MemOperand FieldMemOperand(Register object, int offset) {
// Generate a MemOperand for storing arguments 5..N on the stack
// when calling CallCFunction().
static inline MemOperand CFunctionArgumentOperand(int index) {
- ASSERT(index > StandardFrameConstants::kCArgSlotCount);
+ ASSERT(index > kCArgSlotCount);
// Argument 5 takes the slot just past the four Arg-slots.
- int offset =
- (index - 5) * kPointerSize + StandardFrameConstants::kCArgsSlotsSize;
+ int offset = (index - 5) * kPointerSize + kCArgsSlotsSize;
return MemOperand(sp, offset);
}
diff --git a/src/mips/regexp-macro-assembler-mips.h b/src/mips/regexp-macro-assembler-mips.h
index 7fe0c886..d42d4cf6 100644
--- a/src/mips/regexp-macro-assembler-mips.h
+++ b/src/mips/regexp-macro-assembler-mips.h
@@ -118,6 +118,7 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
static int CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame);
+
private:
// Offsets from frame_pointer() of function parameters and stored registers.
static const int kFramePointer = 0;
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 3b386953..17c18977 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -33,6 +33,7 @@
#if defined(V8_TARGET_ARCH_MIPS)
+#include "cpu.h"
#include "disasm.h"
#include "assembler.h"
#include "globals.h" // Need the BitCast.
@@ -1215,6 +1216,8 @@ int32_t Simulator::get_pc() const {
int Simulator::ReadW(int32_t addr, Instruction* instr) {
if (addr >=0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
+ PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
+ addr, reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
@@ -1234,6 +1237,8 @@ int Simulator::ReadW(int32_t addr, Instruction* instr) {
void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
if (addr >= 0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
+ PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
+ addr, reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
@@ -2716,7 +2721,7 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) {
// Store remaining arguments on stack, from low to high memory.
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
for (int i = 4; i < argument_count; i++) {
- stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t);
+ stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
}
va_end(parameters);
set_register(sp, entry_stack);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index c17a658d..5b949734 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3099,7 +3099,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
// -- a1 : receiver
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(a1,
@@ -3191,7 +3191,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
// -- a3 : scratch
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -3442,25 +3442,25 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
}
-static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
+static bool IsElementTypeSigned(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
return true;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
return false;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
return false;
}
@@ -3470,7 +3470,7 @@ static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- ra : return address
// -- a0 : key
@@ -3501,36 +3501,36 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// We are not untagging smi key and instead work with it
// as if it was premultiplied by 2.
- ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
+ STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
Register value = a2;
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ srl(t2, key, 1);
__ addu(t3, a3, t2);
__ lb(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ srl(t2, key, 1);
__ addu(t3, a3, t2);
__ lbu(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ addu(t3, a3, key);
__ lh(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ addu(t3, a3, key);
__ lhu(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t2, key, 1);
__ addu(t3, a3, t2);
__ lw(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ sll(t3, t2, 2);
__ addu(t3, a3, t3);
if (CpuFeatures::IsSupported(FPU)) {
@@ -3540,7 +3540,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ lw(value, MemOperand(t3, 0));
}
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t2, key, 2);
__ addu(t3, a3, t2);
if (CpuFeatures::IsSupported(FPU)) {
@@ -3552,10 +3552,10 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ lw(a3, MemOperand(t3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3569,7 +3569,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// f0: value (if FPU is supported)
// a2/a3: value (if FPU is not supported)
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3611,7 +3611,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3682,7 +3682,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ mov(v0, t2);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
if (CpuFeatures::IsSupported(FPU)) {
@@ -3749,7 +3749,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
// Allocate a HeapNumber for the result. Don't use a0 and a1 as
@@ -3803,7 +3803,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- a0 : value
// -- a1 : key
@@ -3838,7 +3838,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// a3: external array.
// t0: key (integer).
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
} else {
@@ -3852,7 +3852,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// t1: value (integer).
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
// Clamp the value to [0..255].
// v0 is used as a scratch register here.
Label done;
@@ -3869,28 +3869,28 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ sb(t1, MemOperand(t8, 0));
}
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t8, t0, 3);
__ addu(a3, a3, t8);
// a3: effective address of the double element
@@ -3912,10 +3912,10 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ sw(t3, MemOperand(a3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3924,7 +3924,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ mov(v0, value);
__ Ret();
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
// a3: external array.
// t0: index (integer).
__ bind(&check_heap_number);
@@ -3945,12 +3945,12 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvt_s_d(f0, f0);
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ swc1(f0, MemOperand(t8, 0));
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, t0, 3);
__ addu(t8, a3, t8);
__ sdc1(f0, MemOperand(t8, 0));
@@ -3958,30 +3958,30 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3997,7 +3997,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
__ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Label done, nan_or_infinity_or_zero;
static const int kMantissaInHiWordShift =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
@@ -4062,7 +4062,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ srl(t4, t4, kMantissaInLoWordShift);
__ or_(t3, t6, t4);
__ Branch(&done);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, t0, 3);
__ addu(t8, a3, t8);
// t8: effective address of destination element.
@@ -4128,30 +4128,30 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Result is in t3.
// This switch block should be exactly the same as above (FPU mode).
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -4213,7 +4213,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// Load the result and make sure it's not the hole.
__ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, t0, a3);
__ lw(t0, MemOperand(t0));
@@ -4344,7 +4344,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
__ Addu(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
__ Addu(scratch3, scratch2, scratch);
__ sw(value_reg, MemOperand(scratch3));
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 4f5fe96a..a791dbba 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -29,8 +29,6 @@
#include <bzlib.h>
#endif
#include <signal.h>
-#include <string>
-#include <map>
#include "v8.h"
@@ -86,16 +84,6 @@ class CounterCollection {
};
-// We statically allocate a set of local counters to be used if we
-// don't want to store the stats in a memory-mapped file
-static CounterCollection local_counters;
-
-
-typedef std::map<std::string, int*> CounterMap;
-typedef std::map<std::string, int*>::iterator CounterMapIterator;
-static CounterMap counter_table_;
-
-
class Compressor {
public:
virtual ~Compressor() {}
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 4da360b8..8de7162a 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -164,6 +164,9 @@ void HeapObject::HeapObjectVerify() {
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyVerify();
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::cast(this)->JSFunctionProxyVerify();
+ break;
case FOREIGN_TYPE:
Foreign::cast(this)->ForeignVerify();
break;
@@ -257,9 +260,9 @@ void JSObject::JSObjectVerify() {
(map()->inobject_properties() + properties()->length() -
map()->NextFreePropertyIndex()));
}
- ASSERT(map()->has_fast_elements() ==
- (elements()->map() == GetHeap()->fixed_array_map() ||
- elements()->map() == GetHeap()->fixed_cow_array_map()));
+ ASSERT_EQ(map()->has_fast_elements(),
+ (elements()->map() == GetHeap()->fixed_array_map() ||
+ elements()->map() == GetHeap()->fixed_cow_array_map()));
ASSERT(map()->has_fast_elements() == HasFastElements());
}
@@ -536,6 +539,15 @@ void JSProxy::JSProxyVerify() {
VerifyPointer(handler());
}
+
+void JSFunctionProxy::JSFunctionProxyVerify() {
+ ASSERT(IsJSFunctionProxy());
+ JSProxyVerify();
+ VerifyPointer(call_trap());
+ VerifyPointer(construct_trap());
+}
+
+
void Foreign::ForeignVerify() {
ASSERT(IsForeign());
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index ff3be03b..8796865c 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2004,7 +2004,7 @@ bool DescriptorArray::IsProperty(int descriptor_number) {
bool DescriptorArray::IsTransition(int descriptor_number) {
PropertyType t = GetType(descriptor_number);
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
- t == EXTERNAL_ARRAY_TRANSITION;
+ t == ELEMENTS_TRANSITION;
}
@@ -2871,7 +2871,7 @@ Code::Flags Code::flags() {
void Code::set_flags(Code::Flags flags) {
- STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1);
+ STATIC_ASSERT(Code::NUMBER_OF_KINDS <= KindField::kMax + 1);
// Make sure that all call stubs have an arguments count.
ASSERT((ExtractKindFromFlags(flags) != CALL_IC &&
ExtractKindFromFlags(flags) != KEYED_CALL_IC) ||
@@ -2885,11 +2885,6 @@ Code::Kind Code::kind() {
}
-InLoopFlag Code::ic_in_loop() {
- return ExtractICInLoopFromFlags(flags());
-}
-
-
InlineCacheState Code::ic_state() {
InlineCacheState result = ExtractICStateFromFlags(flags());
// Only allow uninitialized or debugger states for non-IC code
@@ -2955,13 +2950,31 @@ void Code::set_optimizable(bool value) {
bool Code::has_deoptimization_support() {
ASSERT(kind() == FUNCTION);
- return READ_BYTE_FIELD(this, kHasDeoptimizationSupportOffset) == 1;
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsHasDeoptimizationSupportField::decode(flags);
}
void Code::set_has_deoptimization_support(bool value) {
ASSERT(kind() == FUNCTION);
- WRITE_BYTE_FIELD(this, kHasDeoptimizationSupportOffset, value ? 1 : 0);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsHasDeoptimizationSupportField::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
+}
+
+
+bool Code::has_debug_break_slots() {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsHasDebugBreakSlotsField::decode(flags);
+}
+
+
+void Code::set_has_debug_break_slots(bool value) {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsHasDebugBreakSlotsField::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
}
@@ -3095,7 +3108,6 @@ bool Code::is_inline_cache_stub() {
Code::Flags Code::ComputeFlags(Kind kind,
- InLoopFlag in_loop,
InlineCacheState ic_state,
ExtraICState extra_ic_state,
PropertyType type,
@@ -3104,26 +3116,17 @@ Code::Flags Code::ComputeFlags(Kind kind,
// Extra IC state is only allowed for call IC stubs or for store IC
// stubs.
ASSERT(extra_ic_state == kNoExtraICState ||
- (kind == CALL_IC) ||
- (kind == STORE_IC) ||
- (kind == KEYED_STORE_IC));
+ kind == CALL_IC ||
+ kind == STORE_IC ||
+ kind == KEYED_STORE_IC);
// Compute the bit mask.
- int bits = kind << kFlagsKindShift;
- if (in_loop) bits |= kFlagsICInLoopMask;
- bits |= ic_state << kFlagsICStateShift;
- bits |= type << kFlagsTypeShift;
- bits |= extra_ic_state << kFlagsExtraICStateShift;
- bits |= argc << kFlagsArgumentsCountShift;
- if (holder == PROTOTYPE_MAP) bits |= kFlagsCacheInPrototypeMapMask;
- // Cast to flags and validate result before returning it.
- Flags result = static_cast<Flags>(bits);
- ASSERT(ExtractKindFromFlags(result) == kind);
- ASSERT(ExtractICStateFromFlags(result) == ic_state);
- ASSERT(ExtractICInLoopFromFlags(result) == in_loop);
- ASSERT(ExtractTypeFromFlags(result) == type);
- ASSERT(ExtractExtraICStateFromFlags(result) == extra_ic_state);
- ASSERT(ExtractArgumentsCountFromFlags(result) == argc);
- return result;
+ int bits = KindField::encode(kind)
+ | ICStateField::encode(ic_state)
+ | TypeField::encode(type)
+ | ExtraICStateField::encode(extra_ic_state)
+ | (argc << kArgumentsCountShift)
+ | CacheHolderField::encode(holder);
+ return static_cast<Flags>(bits);
}
@@ -3131,56 +3134,43 @@ Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
PropertyType type,
ExtraICState extra_ic_state,
InlineCacheHolderFlag holder,
- InLoopFlag in_loop,
int argc) {
- return ComputeFlags(
- kind, in_loop, MONOMORPHIC, extra_ic_state, type, argc, holder);
+ return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, argc, holder);
}
Code::Kind Code::ExtractKindFromFlags(Flags flags) {
- int bits = (flags & kFlagsKindMask) >> kFlagsKindShift;
- return static_cast<Kind>(bits);
+ return KindField::decode(flags);
}
InlineCacheState Code::ExtractICStateFromFlags(Flags flags) {
- int bits = (flags & kFlagsICStateMask) >> kFlagsICStateShift;
- return static_cast<InlineCacheState>(bits);
+ return ICStateField::decode(flags);
}
Code::ExtraICState Code::ExtractExtraICStateFromFlags(Flags flags) {
- int bits = (flags & kFlagsExtraICStateMask) >> kFlagsExtraICStateShift;
- return static_cast<ExtraICState>(bits);
-}
-
-
-InLoopFlag Code::ExtractICInLoopFromFlags(Flags flags) {
- int bits = (flags & kFlagsICInLoopMask);
- return bits != 0 ? IN_LOOP : NOT_IN_LOOP;
+ return ExtraICStateField::decode(flags);
}
PropertyType Code::ExtractTypeFromFlags(Flags flags) {
- int bits = (flags & kFlagsTypeMask) >> kFlagsTypeShift;
- return static_cast<PropertyType>(bits);
+ return TypeField::decode(flags);
}
int Code::ExtractArgumentsCountFromFlags(Flags flags) {
- return (flags & kFlagsArgumentsCountMask) >> kFlagsArgumentsCountShift;
+ return (flags & kArgumentsCountMask) >> kArgumentsCountShift;
}
InlineCacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
- int bits = (flags & kFlagsCacheInPrototypeMapMask);
- return bits != 0 ? PROTOTYPE_MAP : OWN_MAP;
+ return CacheHolderField::decode(flags);
}
Code::Flags Code::RemoveTypeFromFlags(Flags flags) {
- int bits = flags & ~kFlagsTypeMask;
+ int bits = flags & ~TypeField::kMask;
return static_cast<Flags>(bits);
}
@@ -3263,7 +3253,7 @@ MaybeObject* Map::GetFastElementsMap() {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::FAST_ELEMENTS);
+ new_map->set_elements_kind(FAST_ELEMENTS);
isolate()->counters()->map_to_fast_elements()->Increment();
return new_map;
}
@@ -3276,7 +3266,7 @@ MaybeObject* Map::GetFastDoubleElementsMap() {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::FAST_DOUBLE_ELEMENTS);
+ new_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
isolate()->counters()->map_to_fast_double_elements()->Increment();
return new_map;
}
@@ -3289,7 +3279,7 @@ MaybeObject* Map::GetSlowElementsMap() {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::DICTIONARY_ELEMENTS);
+ new_map->set_elements_kind(DICTIONARY_ELEMENTS);
isolate()->counters()->map_to_slow_elements()->Increment();
return new_map;
}
@@ -3920,7 +3910,16 @@ void JSBuiltinsObject::set_javascript_builtin_code(Builtins::JavaScript id,
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
-ACCESSORS(JSProxy, padding, Object, kPaddingOffset)
+ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset)
+ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset)
+
+
+void JSProxy::InitializeBody(int object_size, Object* value) {
+ ASSERT(!value->IsHeapObject() || !GetHeap()->InNewSpace(value));
+ for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
+ WRITE_FIELD(this, offset, value);
+ }
+}
ACCESSORS(JSWeakMap, table, ObjectHashTable, kTableOffset)
@@ -4102,7 +4101,7 @@ void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) {
}
-JSObject::ElementsKind JSObject::GetElementsKind() {
+ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
ASSERT((kind == FAST_ELEMENTS &&
(elements()->map() == GetHeap()->fixed_array_map() ||
@@ -4441,9 +4440,7 @@ PropertyAttributes AccessorInfo::property_attributes() {
void AccessorInfo::set_property_attributes(PropertyAttributes attributes) {
- ASSERT(AttributesField::is_valid(attributes));
- int rest_value = flag()->value() & ~AttributesField::mask();
- set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes)));
+ set_flag(Smi::FromInt(AttributesField::update(flag()->value(), attributes)));
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 35735724..0398572f 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -151,6 +151,9 @@ void HeapObject::HeapObjectPrint(FILE* out) {
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyPrint(out);
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::cast(this)->JSFunctionProxyPrint(out);
+ break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapPrint(out);
break;
@@ -588,6 +591,19 @@ void JSProxy::JSProxyPrint(FILE* out) {
}
+void JSFunctionProxy::JSFunctionProxyPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSFunctionProxy");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - handler = ");
+ handler()->Print(out);
+ PrintF(out, " - call_trap = ");
+ call_trap()->Print(out);
+ PrintF(out, " - construct_trap = ");
+ construct_trap()->Print(out);
+ PrintF(out, "\n");
+}
+
+
void JSWeakMap::JSWeakMapPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSWeakMap");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index bde9e831..0aa21dd6 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -105,6 +105,11 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
kVisitStructGeneric,
JSProxy::kSize);
+ case JS_FUNCTION_PROXY_TYPE:
+ return GetVisitorIdForSize(kVisitStruct,
+ kVisitStructGeneric,
+ JSFunctionProxy::kSize);
+
case FOREIGN_TYPE:
return GetVisitorIdForSize(kVisitDataObject,
kVisitDataObjectGeneric,
diff --git a/src/objects.cc b/src/objects.cc
index 0660dbaa..6085b4ef 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -41,7 +41,6 @@
#include "objects-visiting.h"
#include "macro-assembler.h"
#include "safepoint-table.h"
-#include "scanner-base.h"
#include "string-stream.h"
#include "utils.h"
#include "vm-state-inl.h"
@@ -85,7 +84,7 @@ MaybeObject* Object::ToObject(Context* global_context) {
MaybeObject* Object::ToObject() {
- if (IsJSObject()) {
+ if (IsJSReceiver()) {
return this;
} else if (IsNumber()) {
Isolate* isolate = Isolate::Current();
@@ -238,6 +237,7 @@ MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
// Get the derived `get' property.
trap = isolate->derived_get_trap();
@@ -592,7 +592,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
return holder->GetPropertyWithInterceptor(recvr, name, attributes);
}
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
break;
@@ -628,6 +628,7 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
} else if (heap_object->IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
} else if (heap_object->IsJSProxy()) {
+ // TODO(rossberg): do something
return heap->undefined_value(); // For now...
} else {
// Undefined and null have no indexed properties.
@@ -1048,6 +1049,7 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
global_object ? "Global Object: " : "",
vowel ? "n" : "");
accumulator->Put(str);
+ accumulator->Put('>');
printed = true;
}
}
@@ -1173,6 +1175,12 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
accumulator->Put('>');
break;
+ case JS_PROXY_TYPE:
+ accumulator->Add("<JSProxy>");
+ break;
+ case JS_FUNCTION_PROXY_TYPE:
+ accumulator->Add("<JSFunctionProxy>");
+ break;
case FOREIGN_TYPE:
accumulator->Add("<Foreign>");
break;
@@ -1251,6 +1259,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_PROXY_TYPE:
JSProxy::BodyDescriptor::IterateBody(this, v);
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
+ break;
case FOREIGN_TYPE:
reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
break;
@@ -1435,13 +1446,12 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// it's unrelated to properties.
int descriptor_index = old_descriptors->Search(name);
- // External array transitions are stored in the descriptor for property "",
- // which is not a identifier and should have forced a switch to slow
- // properties above.
+ // Element transitions are stored in the descriptor for property "", which is
+ // not a identifier and should have forced a switch to slow properties above.
ASSERT(descriptor_index == DescriptorArray::kNotFound ||
- old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
+ old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
- old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
+ old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
bool allow_map_transition =
can_insert_transition &&
(isolate->context()->global_context()->object_function()->map() != map());
@@ -1989,61 +1999,25 @@ void Map::LookupInDescriptors(JSObject* holder,
}
-static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
- ExternalArrayType array_type) {
- switch (array_type) {
- case kExternalByteArray:
- return JSObject::EXTERNAL_BYTE_ELEMENTS;
- break;
- case kExternalUnsignedByteArray:
- return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
- break;
- case kExternalShortArray:
- return JSObject::EXTERNAL_SHORT_ELEMENTS;
- break;
- case kExternalUnsignedShortArray:
- return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
- break;
- case kExternalIntArray:
- return JSObject::EXTERNAL_INT_ELEMENTS;
- break;
- case kExternalUnsignedIntArray:
- return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
- break;
- case kExternalFloatArray:
- return JSObject::EXTERNAL_FLOAT_ELEMENTS;
- break;
- case kExternalDoubleArray:
- return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
- break;
- case kExternalPixelArray:
- return JSObject::EXTERNAL_PIXEL_ELEMENTS;
- break;
- }
- UNREACHABLE();
- return JSObject::DICTIONARY_ELEMENTS;
-}
-
-
-MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
- bool safe_to_add_transition) {
+MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind,
+ bool safe_to_add_transition) {
Heap* current_heap = heap();
DescriptorArray* descriptors = instance_descriptors();
- String* external_array_sentinel_name = current_heap->empty_symbol();
+ String* elements_transition_sentinel_name = current_heap->empty_symbol();
if (safe_to_add_transition) {
// It's only safe to manipulate the descriptor array if it would be
// safe to add a transition.
ASSERT(!is_shared()); // no transitions can be added to shared maps.
- // Check if the external array transition already exists.
+ // Check if the elements transition already exists.
DescriptorLookupCache* cache =
current_heap->isolate()->descriptor_lookup_cache();
- int index = cache->Lookup(descriptors, external_array_sentinel_name);
+ int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
if (index == DescriptorLookupCache::kAbsent) {
- index = descriptors->Search(external_array_sentinel_name);
+ index = descriptors->Search(elements_transition_sentinel_name);
cache->Update(descriptors,
- external_array_sentinel_name,
+ elements_transition_sentinel_name,
index);
}
@@ -2051,8 +2025,8 @@ MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
// return it.
if (index != DescriptorArray::kNotFound) {
PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
- if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
- details.array_type() == array_type) {
+ if (details.type() == ELEMENTS_TRANSITION &&
+ details.elements_kind() == elements_kind) {
return descriptors->GetValue(index);
} else {
safe_to_add_transition = false;
@@ -2060,28 +2034,29 @@ MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
}
}
- // No transition to an existing external array map. Make a new one.
+ // No transition to an existing map for the given ElementsKind. Make a new
+ // one.
Object* obj;
{ MaybeObject* maybe_map = CopyDropTransitions();
if (!maybe_map->ToObject(&obj)) return maybe_map;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
+ new_map->set_elements_kind(elements_kind);
GetIsolate()->counters()->map_to_external_array_elements()->Increment();
// Only remember the map transition if the object's map is NOT equal to the
// global object_function's map and there is not an already existing
- // non-matching external array transition.
+ // non-matching element transition.
bool allow_map_transition =
safe_to_add_transition &&
(GetIsolate()->context()->global_context()->object_function()->map() !=
map());
if (allow_map_transition) {
// Allocate new instance descriptors for the old map with map transition.
- ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
- Map::cast(new_map),
- array_type);
+ ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
+ Map::cast(new_map),
+ elements_kind);
Object* new_descriptors;
MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
&desc,
@@ -2248,6 +2223,7 @@ bool JSProxy::HasPropertyWithHandler(String* name_raw) {
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
trap = isolate->derived_has_trap();
}
@@ -2278,6 +2254,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
trap = isolate->derived_set_trap();
}
@@ -2305,6 +2282,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2347,6 +2325,7 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
Handle<String> trap_name =
isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return NONE;
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2373,9 +2352,13 @@ void JSProxy::Fix() {
HandleScope scope(isolate);
Handle<JSProxy> self(this);
- isolate->factory()->BecomeJSObject(self);
+ if (IsJSFunctionProxy()) {
+ isolate->factory()->BecomeJSFunction(self);
+ // Code will be set on the JavaScript side.
+ } else {
+ isolate->factory()->BecomeJSObject(self);
+ }
ASSERT(self->IsJSObject());
- // TODO(rossberg): recognize function proxies.
}
@@ -2498,7 +2481,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
}
case NULL_DESCRIPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2586,7 +2569,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
// if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2867,7 +2850,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
case INTERCEPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
break;
default:
UNREACHABLE();
@@ -5100,13 +5083,13 @@ String::FlatContent String::GetFlatContent() {
}
-SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int offset,
- int length,
- int* length_return) {
+SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int offset,
+ int length,
+ int* length_return) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartPointer<char>(NULL);
+ return SmartArrayPointer<char>(NULL);
}
Heap* heap = GetHeap();
@@ -5150,13 +5133,13 @@ SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
character_position++;
}
result[utf8_byte_position] = 0;
- return SmartPointer<char>(result);
+ return SmartArrayPointer<char>(result);
}
-SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int* length_return) {
+SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int* length_return) {
return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
}
@@ -5187,9 +5170,9 @@ const uc16* String::GetTwoByteData(unsigned start) {
}
-SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
+SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartPointer<uc16>();
+ return SmartArrayPointer<uc16>();
}
Heap* heap = GetHeap();
@@ -5205,7 +5188,7 @@ SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
result[i++] = character;
}
result[i] = 0;
- return SmartPointer<uc16>(result);
+ return SmartArrayPointer<uc16>(result);
}
@@ -6219,7 +6202,7 @@ void Map::CreateBackPointers() {
DescriptorArray* descriptors = instance_descriptors();
for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
if (descriptors->GetType(i) == MAP_TRANSITION ||
- descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
+ descriptors->GetType(i) == ELEMENTS_TRANSITION ||
descriptors->GetType(i) == CONSTANT_TRANSITION) {
// Get target.
Map* target = Map::cast(descriptors->GetValue(i));
@@ -6262,7 +6245,7 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
// non-live object.
PropertyDetails details(Smi::cast(contents->get(i + 1)));
if (details.type() == MAP_TRANSITION ||
- details.type() == EXTERNAL_ARRAY_TRANSITION ||
+ details.type() == ELEMENTS_TRANSITION ||
details.type() == CONSTANT_TRANSITION) {
Map* target = reinterpret_cast<Map*>(contents->get(i));
ASSERT(target->IsHeapObject());
@@ -6422,7 +6405,7 @@ Object* JSFunction::SetInstanceClassName(String* name) {
void JSFunction::PrintName(FILE* out) {
- SmartPointer<char> name = shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
PrintF(out, "%s", *name);
}
@@ -7026,7 +7009,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
JSFunction* function =
JSFunction::cast(LiteralArray()->get(function_id));
unsigned height = iterator.Next();
- PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
+ PrintF(out, "{ast_id=%d, function=", ast_id);
function->PrintName(out);
PrintF(out, ", height=%u}", height);
break;
@@ -7151,7 +7134,7 @@ const char* Code::PropertyType2String(PropertyType type) {
case HANDLER: return "HANDLER";
case INTERCEPTOR: return "INTERCEPTOR";
case MAP_TRANSITION: return "MAP_TRANSITION";
- case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
+ case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
@@ -7190,7 +7173,6 @@ void Code::Disassemble(const char* name, FILE* out) {
if (is_inline_cache_stub()) {
PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
PrintExtraICState(out, kind(), extra_ic_state());
- PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", PropertyType2String(type()));
}
@@ -7541,7 +7523,7 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap());
- JSObject::ElementsKind elements_kind = GetElementsKind();
+ ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
@@ -10151,6 +10133,8 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
// If the object is in dictionary mode, it is converted to fast elements
// mode.
MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
+ ASSERT(!HasExternalArrayElements());
+
Heap* heap = GetHeap();
if (HasDictionaryElements()) {
@@ -10180,9 +10164,6 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
set_map(new_map);
set_elements(fast_elements);
- } else if (HasExternalArrayElements()) {
- // External arrays cannot have holes or undefined elements.
- return Smi::FromInt(ExternalArray::cast(elements())->length());
} else if (!HasFastDoubleElements()) {
Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
diff --git a/src/objects.h b/src/objects.h
index 53ba981c..d9c7a822 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -31,7 +31,7 @@
#include "allocation.h"
#include "builtins.h"
#include "list.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "unicode-inl.h"
#if V8_TARGET_ARCH_ARM
#include "arm/constants-arm.h"
@@ -135,6 +135,37 @@ enum PropertyAttributes {
namespace v8 {
namespace internal {
+enum ElementsKind {
+ // The "fast" kind for tagged values. Must be first to make it possible
+ // to efficiently check maps if they have fast elements.
+ FAST_ELEMENTS,
+
+ // The "fast" kind for unwrapped, non-tagged double values.
+ FAST_DOUBLE_ELEMENTS,
+
+ // The "slow" kind.
+ DICTIONARY_ELEMENTS,
+ NON_STRICT_ARGUMENTS_ELEMENTS,
+ // The "fast" kind for external arrays
+ EXTERNAL_BYTE_ELEMENTS,
+ EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
+ EXTERNAL_SHORT_ELEMENTS,
+ EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
+ EXTERNAL_INT_ELEMENTS,
+ EXTERNAL_UNSIGNED_INT_ELEMENTS,
+ EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_DOUBLE_ELEMENTS,
+ EXTERNAL_PIXEL_ELEMENTS,
+
+ // Derived constants from ElementsKind
+ FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
+ LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
+ FIRST_ELEMENTS_KIND = FAST_ELEMENTS,
+ LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
+};
+
+static const int kElementsKindCount =
+ LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
// PropertyDetails captures type and attributes for a property.
// They are used both in property dictionaries and instance descriptors.
@@ -143,7 +174,7 @@ class PropertyDetails BASE_EMBEDDED {
PropertyDetails(PropertyAttributes attributes,
PropertyType type,
int index = 0) {
- ASSERT(type != EXTERNAL_ARRAY_TRANSITION);
+ ASSERT(type != ELEMENTS_TRANSITION);
ASSERT(TypeField::is_valid(type));
ASSERT(AttributesField::is_valid(attributes));
ASSERT(StorageField::is_valid(index));
@@ -159,19 +190,19 @@ class PropertyDetails BASE_EMBEDDED {
PropertyDetails(PropertyAttributes attributes,
PropertyType type,
- ExternalArrayType array_type) {
- ASSERT(type == EXTERNAL_ARRAY_TRANSITION);
+ ElementsKind elements_kind) {
+ ASSERT(type == ELEMENTS_TRANSITION);
ASSERT(TypeField::is_valid(type));
ASSERT(AttributesField::is_valid(attributes));
- ASSERT(StorageField::is_valid(static_cast<int>(array_type)));
+ ASSERT(StorageField::is_valid(static_cast<int>(elements_kind)));
value_ = TypeField::encode(type)
| AttributesField::encode(attributes)
- | StorageField::encode(static_cast<int>(array_type));
+ | StorageField::encode(static_cast<int>(elements_kind));
ASSERT(type == this->type());
ASSERT(attributes == this->attributes());
- ASSERT(array_type == this->array_type());
+ ASSERT(elements_kind == this->elements_kind());
}
// Conversion for storing details as Object*.
@@ -184,7 +215,7 @@ class PropertyDetails BASE_EMBEDDED {
PropertyType t = type();
ASSERT(t != INTERCEPTOR);
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
- t == EXTERNAL_ARRAY_TRANSITION;
+ t == ELEMENTS_TRANSITION;
}
bool IsProperty() {
@@ -195,9 +226,9 @@ class PropertyDetails BASE_EMBEDDED {
int index() { return StorageField::decode(value_); }
- ExternalArrayType array_type() {
- ASSERT(type() == EXTERNAL_ARRAY_TRANSITION);
- return static_cast<ExternalArrayType>(StorageField::decode(value_));
+ ElementsKind elements_kind() {
+ ASSERT(type() == ELEMENTS_TRANSITION);
+ return static_cast<ElementsKind>(StorageField::decode(value_));
}
inline PropertyDetails AsDeleted();
@@ -1463,38 +1494,6 @@ class JSReceiver: public HeapObject {
// caching.
class JSObject: public JSReceiver {
public:
- enum ElementsKind {
- // The "fast" kind for tagged values. Must be first to make it possible
- // to efficiently check maps if they have fast elements.
- FAST_ELEMENTS,
-
- // The "fast" kind for unwrapped, non-tagged double values.
- FAST_DOUBLE_ELEMENTS,
-
- // The "slow" kind.
- DICTIONARY_ELEMENTS,
- NON_STRICT_ARGUMENTS_ELEMENTS,
- // The "fast" kind for external arrays
- EXTERNAL_BYTE_ELEMENTS,
- EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
- EXTERNAL_SHORT_ELEMENTS,
- EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
- EXTERNAL_INT_ELEMENTS,
- EXTERNAL_UNSIGNED_INT_ELEMENTS,
- EXTERNAL_FLOAT_ELEMENTS,
- EXTERNAL_DOUBLE_ELEMENTS,
- EXTERNAL_PIXEL_ELEMENTS,
-
- // Derived constants from ElementsKind
- FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
- LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
- FIRST_ELEMENTS_KIND = FAST_ELEMENTS,
- LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
- };
-
- static const int kElementsKindCount =
- LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
-
// [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case and a Dictionary in the
// slow case.
@@ -3154,7 +3153,6 @@ class ByteArray: public FixedArrayBase {
// raised rather than being silently ignored.
class ExternalArray: public FixedArrayBase {
public:
-
inline bool is_the_hole(int index) { return false; }
// [external_pointer]: The pointer to the external memory area backing this
@@ -3655,7 +3653,6 @@ class Code: public HeapObject {
inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline ExtraICState extra_ic_state(); // Only valid for IC stubs.
- inline InLoopFlag ic_in_loop(); // Only valid for IC stubs.
inline PropertyType type(); // Only valid for monomorphic IC stubs.
inline int arguments_count(); // Only valid for call IC stubs.
@@ -3685,6 +3682,11 @@ class Code: public HeapObject {
inline bool has_deoptimization_support();
inline void set_has_deoptimization_support(bool value);
+ // [has_debug_break_slots]: For FUNCTION kind, tells if it has
+ // been compiled with debug break slots.
+ inline bool has_debug_break_slots();
+ inline void set_has_debug_break_slots(bool value);
+
// [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
// how long the function has been marked for OSR and therefore which
// level of loop nesting we are willing to do on-stack replacement
@@ -3743,7 +3745,6 @@ class Code: public HeapObject {
// Flags operations.
static inline Flags ComputeFlags(
Kind kind,
- InLoopFlag in_loop = NOT_IN_LOOP,
InlineCacheState ic_state = UNINITIALIZED,
ExtraICState extra_ic_state = kNoExtraICState,
PropertyType type = NORMAL,
@@ -3755,16 +3756,15 @@ class Code: public HeapObject {
PropertyType type,
ExtraICState extra_ic_state = kNoExtraICState,
InlineCacheHolderFlag holder = OWN_MAP,
- InLoopFlag in_loop = NOT_IN_LOOP,
int argc = -1);
- static inline Kind ExtractKindFromFlags(Flags flags);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
- static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
- static inline InLoopFlag ExtractICInLoopFromFlags(Flags flags);
static inline PropertyType ExtractTypeFromFlags(Flags flags);
- static inline int ExtractArgumentsCountFromFlags(Flags flags);
+ static inline Kind ExtractKindFromFlags(Flags flags);
static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
+ static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
+ static inline int ExtractArgumentsCountFromFlags(Flags flags);
+
static inline Flags RemoveTypeFromFlags(Flags flags);
// Convert a target address into a code object.
@@ -3875,34 +3875,32 @@ class Code: public HeapObject {
static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1;
static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
static const int kToBooleanTypeOffset = kStubMajorKeyOffset + 1;
- static const int kHasDeoptimizationSupportOffset = kOptimizableOffset + 1;
+
+ static const int kFullCodeFlags = kOptimizableOffset + 1;
+ class FullCodeFlagsHasDeoptimizationSupportField:
+ public BitField<bool, 0, 1> {}; // NOLINT
+ class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
- static const int kAllowOSRAtLoopNestingLevelOffset =
- kHasDeoptimizationSupportOffset + 1;
+
+ static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1;
static const int kSafepointTableOffsetOffset = kStackSlotsOffset + kIntSize;
static const int kStackCheckTableOffsetOffset = kStackSlotsOffset + kIntSize;
- // Flags layout.
- static const int kFlagsICStateShift = 0;
- static const int kFlagsICInLoopShift = 3;
- static const int kFlagsTypeShift = 4;
- static const int kFlagsKindShift = 8;
- static const int kFlagsICHolderShift = 12;
- static const int kFlagsExtraICStateShift = 13;
- static const int kFlagsArgumentsCountShift = 15;
-
- static const int kFlagsICStateMask = 0x00000007; // 00000000111
- static const int kFlagsICInLoopMask = 0x00000008; // 00000001000
- static const int kFlagsTypeMask = 0x000000F0; // 00001110000
- static const int kFlagsKindMask = 0x00000F00; // 11110000000
- static const int kFlagsCacheInPrototypeMapMask = 0x00001000;
- static const int kFlagsExtraICStateMask = 0x00006000;
- static const int kFlagsArgumentsCountMask = 0xFFFF8000;
+ // Flags layout. BitField<type, shift, size>.
+ class ICStateField: public BitField<InlineCacheState, 0, 3> {};
+ class TypeField: public BitField<PropertyType, 3, 4> {};
+ class KindField: public BitField<Kind, 7, 4> {};
+ class CacheHolderField: public BitField<InlineCacheHolderFlag, 11, 1> {};
+ class ExtraICStateField: public BitField<ExtraICState, 12, 2> {};
+
+ // Signed field cannot be encoded using the BitField class.
+ static const int kArgumentsCountShift = 14;
+ static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
static const int kFlagsNotUsedInLookup =
- (kFlagsICInLoopMask | kFlagsTypeMask | kFlagsCacheInPrototypeMapMask);
+ TypeField::kMask | CacheHolderField::kMask;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
@@ -4021,37 +4019,37 @@ class Map: public HeapObject {
inline void set_is_extensible(bool value);
inline bool is_extensible();
- inline void set_elements_kind(JSObject::ElementsKind elements_kind) {
- ASSERT(elements_kind < JSObject::kElementsKindCount);
- ASSERT(JSObject::kElementsKindCount <= (1 << kElementsKindBitCount));
+ inline void set_elements_kind(ElementsKind elements_kind) {
+ ASSERT(elements_kind < kElementsKindCount);
+ ASSERT(kElementsKindCount <= (1 << kElementsKindBitCount));
set_bit_field2((bit_field2() & ~kElementsKindMask) |
(elements_kind << kElementsKindShift));
ASSERT(this->elements_kind() == elements_kind);
}
- inline JSObject::ElementsKind elements_kind() {
- return static_cast<JSObject::ElementsKind>(
+ inline ElementsKind elements_kind() {
+ return static_cast<ElementsKind>(
(bit_field2() & kElementsKindMask) >> kElementsKindShift);
}
// Tells whether the instance has fast elements.
// Equivalent to instance->GetElementsKind() == FAST_ELEMENTS.
inline bool has_fast_elements() {
- return elements_kind() == JSObject::FAST_ELEMENTS;
+ return elements_kind() == FAST_ELEMENTS;
}
inline bool has_fast_double_elements() {
- return elements_kind() == JSObject::FAST_DOUBLE_ELEMENTS;
+ return elements_kind() == FAST_DOUBLE_ELEMENTS;
}
inline bool has_external_array_elements() {
- JSObject::ElementsKind kind(elements_kind());
- return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
- kind <= JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
+ ElementsKind kind(elements_kind());
+ return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
+ kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
}
inline bool has_dictionary_elements() {
- return elements_kind() == JSObject::DICTIONARY_ELEMENTS;
+ return elements_kind() == DICTIONARY_ELEMENTS;
}
// Tells whether the map is attached to SharedFunctionInfo
@@ -4156,9 +4154,9 @@ class Map: public HeapObject {
MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap();
// Returns a new map with all transitions dropped from the descriptors and the
- // ElementsKind set to one of the value corresponding to array_type.
- MUST_USE_RESULT MaybeObject* GetExternalArrayElementsMap(
- ExternalArrayType array_type,
+ // ElementsKind set.
+ MUST_USE_RESULT MaybeObject* GetElementsTransitionMap(
+ ElementsKind elements_kind,
bool safe_to_add_transition);
// Returns the property index for name (only valid for FAST MODE).
@@ -4323,7 +4321,7 @@ class Map: public HeapObject {
static const int kElementsKindMask = (-1 << kElementsKindShift) &
((1 << (kElementsKindShift + kElementsKindBitCount)) - 1);
static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>(
- (JSObject::FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
+ (FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
// Bit positions for bit field 3
static const int kIsShared = 0;
@@ -4737,7 +4735,7 @@ class SharedFunctionInfo: public HeapObject {
DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
// Indicates whether the function is a native function.
- // These needs special threatment in .call and .apply since
+ // These needs special treatment in .call and .apply since
// null passed as the receiver should not be translated to the
// global object.
DECL_BOOLEAN_ACCESSORS(native)
@@ -5004,7 +5002,7 @@ class JSFunction: public JSObject {
// [prototype_or_initial_map]:
DECL_ACCESSORS(prototype_or_initial_map, Object)
- // [shared_function_info]: The information about the function that
+ // [shared]: The information about the function that
// can be shared by instances.
DECL_ACCESSORS(shared, SharedFunctionInfo)
@@ -5981,12 +5979,12 @@ class String: public HeapObject {
// ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it
// handles unexpected data without causing assert failures and it does not
// do any heap allocations. This is useful when printing stack traces.
- SmartPointer<char> ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robustness_flag,
- int offset,
- int length,
- int* length_output = 0);
- SmartPointer<char> ToCString(
+ SmartArrayPointer<char> ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robustness_flag,
+ int offset,
+ int length,
+ int* length_output = 0);
+ SmartArrayPointer<char> ToCString(
AllowNullsFlag allow_nulls = DISALLOW_NULLS,
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
int* length_output = 0);
@@ -5999,7 +5997,7 @@ class String: public HeapObject {
// ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it
// handles unexpected data without causing assert failures and it does not
// do any heap allocations. This is useful when printing stack traces.
- SmartPointer<uc16> ToWideCString(
+ SmartArrayPointer<uc16> ToWideCString(
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL);
// Tells whether the hash code has been computed.
@@ -6409,7 +6407,6 @@ class ConsString: public String {
// - truncating sliced string to enable otherwise unneeded parent to be GC'ed.
class SlicedString: public String {
public:
-
inline String* parent();
inline void set_parent(String* parent);
inline int offset();
@@ -6722,9 +6719,6 @@ class JSProxy: public JSReceiver {
// [handler]: The handler property.
DECL_ACCESSORS(handler, Object)
- // [padding]: The padding slot (unused, see below).
- DECL_ACCESSORS(padding, Object)
-
// Casting.
static inline JSProxy* cast(Object* obj);
@@ -6748,6 +6742,9 @@ class JSProxy: public JSReceiver {
// Turn this into an (empty) JSObject.
void Fix();
+ // Initializes the body after the handler slot.
+ inline void InitializeBody(int object_size, Object* value);
+
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSProxyPrint() {
@@ -6764,9 +6761,11 @@ class JSProxy: public JSReceiver {
// upon freeze.
static const int kHandlerOffset = HeapObject::kHeaderSize;
static const int kPaddingOffset = kHandlerOffset + kPointerSize;
- static const int kSize = kPaddingOffset + kPointerSize;
+ static const int kSize = JSObject::kHeaderSize;
+ static const int kHeaderSize = kPaddingOffset;
+ static const int kPaddingSize = kSize - kPaddingOffset;
- STATIC_CHECK(kSize == JSObject::kHeaderSize);
+ STATIC_CHECK(kPaddingSize >= 0);
typedef FixedBodyDescriptor<kHandlerOffset,
kHandlerOffset + kPointerSize,
@@ -6777,12 +6776,41 @@ class JSProxy: public JSReceiver {
};
-// TODO(rossberg): Only a stub for now.
class JSFunctionProxy: public JSProxy {
public:
+ // [call_trap]: The call trap.
+ DECL_ACCESSORS(call_trap, Object)
+
+ // [construct_trap]: The construct trap.
+ DECL_ACCESSORS(construct_trap, Object)
+
// Casting.
static inline JSFunctionProxy* cast(Object* obj);
+ // Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSFunctionProxyPrint() {
+ JSFunctionProxyPrint(stdout);
+ }
+ void JSFunctionProxyPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSFunctionProxyVerify();
+#endif
+
+ // Layout description.
+ static const int kCallTrapOffset = kHandlerOffset + kPointerSize;
+ static const int kConstructTrapOffset = kCallTrapOffset + kPointerSize;
+ static const int kPaddingOffset = kConstructTrapOffset + kPointerSize;
+ static const int kSize = JSFunction::kSize;
+ static const int kPaddingSize = kSize - kPaddingOffset;
+
+ STATIC_CHECK(kPaddingSize >= 0);
+
+ typedef FixedBodyDescriptor<kHandlerOffset,
+ kConstructTrapOffset + kPointerSize,
+ kSize> BodyDescriptor;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSFunctionProxy);
};
diff --git a/src/parser.cc b/src/parser.cc
index f8c7c416..f9500c40 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -30,6 +30,7 @@
#include "api.h"
#include "ast-inl.h"
#include "bootstrapper.h"
+#include "char-predicates-inl.h"
#include "codegen.h"
#include "compiler.h"
#include "func-name-inferrer.h"
@@ -38,6 +39,7 @@
#include "platform.h"
#include "preparser.h"
#include "runtime.h"
+#include "scanner-character-streams.h"
#include "scopeinfo.h"
#include "string-stream.h"
@@ -532,7 +534,7 @@ LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
parser->top_scope_ = scope;
parser->lexical_scope_ = this;
parser->with_nesting_level_ = 0;
- isolate->set_ast_node_id(AstNode::kFunctionEntryId + 1);
+ isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
}
@@ -647,6 +649,11 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
if (ok && top_scope_->is_strict_mode()) {
CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
}
+
+ if (ok && harmony_block_scoping_) {
+ CheckConflictingVarDeclarations(scope, &ok);
+ }
+
if (ok) {
result = new(zone()) FunctionLiteral(
isolate(),
@@ -950,18 +957,17 @@ class InitializationBlockFinder : public ParserFinder {
};
-// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
+// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form
// this.x = ...;, where x is a named property. It also determines whether a
// function contains only assignments of this type.
-class ThisNamedPropertyAssignmentFinder : public ParserFinder {
+class ThisNamedPropertyAssigmentFinder : public ParserFinder {
public:
- explicit ThisNamedPropertyAssignmentFinder(Isolate* isolate)
+ explicit ThisNamedPropertyAssigmentFinder(Isolate* isolate)
: isolate_(isolate),
only_simple_this_property_assignments_(true),
- names_(0),
- assigned_arguments_(0),
- assigned_constants_(0) {
- }
+ names_(NULL),
+ assigned_arguments_(NULL),
+ assigned_constants_(NULL) {}
void Update(Scope* scope, Statement* stat) {
// Bail out if function already has property assignment that are
@@ -988,17 +994,19 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder {
// Returns a fixed array containing three elements for each assignment of the
// form this.x = y;
Handle<FixedArray> GetThisPropertyAssignments() {
- if (names_.is_empty()) {
+ if (names_ == NULL) {
return isolate_->factory()->empty_fixed_array();
}
- ASSERT_EQ(names_.length(), assigned_arguments_.length());
- ASSERT_EQ(names_.length(), assigned_constants_.length());
+ ASSERT(names_ != NULL);
+ ASSERT(assigned_arguments_ != NULL);
+ ASSERT_EQ(names_->length(), assigned_arguments_->length());
+ ASSERT_EQ(names_->length(), assigned_constants_->length());
Handle<FixedArray> assignments =
- isolate_->factory()->NewFixedArray(names_.length() * 3);
- for (int i = 0; i < names_.length(); ++i) {
- assignments->set(i * 3, *names_[i]);
- assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i]));
- assignments->set(i * 3 + 2, *assigned_constants_[i]);
+ isolate_->factory()->NewFixedArray(names_->length() * 3);
+ for (int i = 0; i < names_->length(); i++) {
+ assignments->set(i * 3, *names_->at(i));
+ assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i)));
+ assignments->set(i * 3 + 2, *assigned_constants_->at(i));
}
return assignments;
}
@@ -1055,37 +1063,18 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder {
AssignmentFromSomethingElse();
}
-
-
-
- // We will potentially reorder the property assignments, so they must be
- // simple enough that the ordering does not matter.
void AssignmentFromParameter(Handle<String> name, int index) {
- EnsureInitialized();
- for (int i = 0; i < names_.length(); ++i) {
- if (name->Equals(*names_[i])) {
- assigned_arguments_[i] = index;
- assigned_constants_[i] = isolate_->factory()->undefined_value();
- return;
- }
- }
- names_.Add(name);
- assigned_arguments_.Add(index);
- assigned_constants_.Add(isolate_->factory()->undefined_value());
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(index);
+ assigned_constants_->Add(isolate_->factory()->undefined_value());
}
void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
- EnsureInitialized();
- for (int i = 0; i < names_.length(); ++i) {
- if (name->Equals(*names_[i])) {
- assigned_arguments_[i] = -1;
- assigned_constants_[i] = value;
- return;
- }
- }
- names_.Add(name);
- assigned_arguments_.Add(-1);
- assigned_constants_.Add(value);
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(-1);
+ assigned_constants_->Add(value);
}
void AssignmentFromSomethingElse() {
@@ -1093,21 +1082,22 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder {
only_simple_this_property_assignments_ = false;
}
- void EnsureInitialized() {
- if (names_.capacity() == 0) {
- ASSERT(assigned_arguments_.capacity() == 0);
- ASSERT(assigned_constants_.capacity() == 0);
- names_.Initialize(4);
- assigned_arguments_.Initialize(4);
- assigned_constants_.Initialize(4);
+ void EnsureAllocation() {
+ if (names_ == NULL) {
+ ASSERT(assigned_arguments_ == NULL);
+ ASSERT(assigned_constants_ == NULL);
+ Zone* zone = isolate_->zone();
+ names_ = new(zone) ZoneStringList(4);
+ assigned_arguments_ = new(zone) ZoneList<int>(4);
+ assigned_constants_ = new(zone) ZoneObjectList(4);
}
}
Isolate* isolate_;
bool only_simple_this_property_assignments_;
- ZoneStringList names_;
- ZoneList<int> assigned_arguments_;
- ZoneObjectList assigned_constants_;
+ ZoneStringList* names_;
+ ZoneList<int>* assigned_arguments_;
+ ZoneObjectList* assigned_constants_;
};
@@ -1144,7 +1134,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
ASSERT(processor != NULL);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
- ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate());
+ ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate());
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
@@ -1360,14 +1350,32 @@ VariableProxy* Parser::Declare(Handle<String> name,
// Declare the name.
var = declaration_scope->DeclareLocal(name, mode);
} else {
- // The name was declared before; check for conflicting re-declarations.
- // We have a conflict if either of the declarations is not a var. There
- // is similar code in runtime.cc in the Declare functions.
+ // The name was declared in this scope before; check for conflicting
+ // re-declarations. We have a conflict if either of the declarations is
+ // not a var. There is similar code in runtime.cc in the Declare
+ // functions. The function CheckNonConflictingScope checks for conflicting
+ // var and let bindings from different scopes whereas this is a check for
+ // conflicting declarations within the same scope. This check also covers
+ //
+ // function () { let x; { var x; } }
+ //
+ // because the var declaration is hoisted to the function scope where 'x'
+ // is already bound.
if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
// We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR ||
var->mode() == Variable::CONST ||
var->mode() == Variable::LET);
+ if (harmony_block_scoping_) {
+ // In harmony mode we treat re-declarations as early errors. See
+ // ES5 16 for a definition of early errors.
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
+ const char* elms[2] = { "Variable", *c_string };
+ Vector<const char*> args(elms, 2);
+ ReportMessage("redeclaration", args);
+ *ok = false;
+ return NULL;
+ }
const char* type = (var->mode() == Variable::VAR) ? "var" :
(var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string =
@@ -1396,8 +1404,10 @@ VariableProxy* Parser::Declare(Handle<String> name,
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
- VariableProxy* proxy = declaration_scope->NewUnresolved(name, false);
- declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
+ VariableProxy* proxy = declaration_scope->NewUnresolved(
+ name, false, scanner().location().beg_pos);
+ declaration_scope->AddDeclaration(
+ new(zone()) Declaration(proxy, mode, fun, top_scope_));
// For global const variables we bind the proxy to a variable.
if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
@@ -1551,9 +1561,6 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
Scope* block_scope = NewScope(top_scope_,
Scope::BLOCK_SCOPE,
inside_with());
- body->set_block_scope(block_scope);
- block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
- Variable::VAR);
if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode();
}
@@ -1576,21 +1583,11 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
}
}
Expect(Token::RBRACE, CHECK_OK);
-
- // Create exit block.
- Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
- exit->AddStatement(new(zone()) ExitContextStatement());
-
- // Create a try-finally statement.
- TryFinallyStatement* try_finally =
- new(zone()) TryFinallyStatement(body, exit);
- try_finally->set_escaping_targets(collector.targets());
top_scope_ = saved_scope;
- // Create a result block.
- Block* result = new(zone()) Block(isolate(), NULL, 1, false);
- result->AddStatement(try_finally);
- return result;
+ block_scope = block_scope->FinalizeBlockScope();
+ body->set_block_scope(block_scope);
+ return body;
}
@@ -1839,18 +1836,21 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
block->AddStatement(new(zone()) ExpressionStatement(initialize));
}
- // Add an assignment node to the initialization statement block if
- // we still have a pending initialization value. We must distinguish
- // between variables and constants: Variable initializations are simply
+ // Add an assignment node to the initialization statement block if we still
+ // have a pending initialization value. We must distinguish between
+ // different kinds of declarations: 'var' initializations are simply
// assignments (with all the consequences if they are inside a 'with'
// statement - they may change a 'with' object property). Constant
// initializations always assign to the declared constant which is
// always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
- // the top context for variables). Sigh...
+ // the top context for var declared variables). Sigh...
+ // For 'let' declared variables the initialization is in the same scope
+ // as the declaration. Thus dynamic lookups are unnecessary even if the
+ // block scope is inside a with.
if (value != NULL) {
- bool in_with = is_const ? false : inside_with();
+ bool in_with = mode == Variable::VAR ? inside_with() : false;
VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment =
@@ -1904,7 +1904,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
// structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
- SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
const char* elms[2] = { "Label", *c_string };
Vector<const char*> args(elms, 2);
ReportMessage("redeclaration", args);
@@ -2219,22 +2219,19 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
- // Rewrite the catch body { B } to a block:
- // { { B } ExitContext; }.
Target target(&this->target_stack_, &catch_collector);
catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode();
}
- catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
- catch_block = new(zone()) Block(isolate(), NULL, 2, false);
+ Variable::Mode mode = harmony_block_scoping_
+ ? Variable::LET : Variable::VAR;
+ catch_variable = catch_scope->DeclareLocal(name, mode);
Scope* saved_scope = top_scope_;
top_scope_ = catch_scope;
- Block* catch_body = ParseBlock(NULL, CHECK_OK);
+ catch_block = ParseBlock(NULL, CHECK_OK);
top_scope_ = saved_scope;
- catch_block->AddStatement(catch_body);
- catch_block->AddStatement(new(zone()) ExitContextStatement());
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@@ -3013,7 +3010,7 @@ void Parser::ReportUnexpectedToken(Token::Value token) {
void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
- SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
const char* element[1] = { *name_string };
ReportMessage("invalid_preparser_data",
Vector<const char*>(element, 1));
@@ -3757,7 +3754,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
reserved_loc = scanner().location();
}
- top_scope_->DeclareParameter(param_name);
+ top_scope_->DeclareParameter(param_name,
+ harmony_block_scoping_
+ ? Variable::LET
+ : Variable::VAR);
num_parameters++;
if (num_parameters > kMaxNumFunctionParameters) {
ReportMessageAt(scanner().location(), "too_many_parameters",
@@ -3884,6 +3884,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
}
}
+ if (harmony_block_scoping_) {
+ CheckConflictingVarDeclarations(scope, CHECK_OK);
+ }
+
FunctionLiteral* function_literal =
new(zone()) FunctionLiteral(isolate(),
function_name,
@@ -4090,6 +4094,25 @@ void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
}
+void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
+ Declaration* decl = scope->CheckConflictingVarDeclarations();
+ if (decl != NULL) {
+ // In harmony mode we treat conflicting variable bindinds as early
+ // errors. See ES5 16 for a definition of early errors.
+ Handle<String> name = decl->proxy()->name();
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
+ const char* elms[2] = { "Variable", *c_string };
+ Vector<const char*> args(elms, 2);
+ int position = decl->proxy()->position();
+ Scanner::Location location = position == RelocInfo::kNoPosition
+ ? Scanner::Location::invalid()
+ : Scanner::Location(position, position + 1);
+ ReportMessageAt(location, "redeclaration", args);
+ *ok = false;
+ }
+}
+
+
// This function reads an identifier name and determines whether or not it
// is 'get' or 'set'.
Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
diff --git a/src/parser.h b/src/parser.h
index 686dac85..3312f2f5 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -30,10 +30,9 @@
#include "allocation.h"
#include "ast.h"
-#include "scanner.h"
-#include "scopes.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
+#include "scopes.h"
namespace v8 {
namespace internal {
@@ -645,6 +644,17 @@ class Parser {
// Strict mode octal literal validation.
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
+ // For harmony block scoping mode: Check if the scope has conflicting var/let
+ // declarations from different scopes. It covers for example
+ //
+ // function f() { { { var x; } let x; } }
+ // function g() { { var x; let x; } }
+ //
+ // The var declarations are hoisted to the function scope, but originate from
+ // a scope where the name has also been let bound or the var declaration is
+ // hoisted over such a scope.
+ void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
+
// Parser support
VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun,
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 85a5e4f6..a72f5da4 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -474,7 +474,6 @@ void Thread::YieldCPU() {
class CygwinMutex : public Mutex {
public:
-
CygwinMutex() {
pthread_mutexattr_t attrs;
memset(&attrs, 0, sizeof(attrs));
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 9d9f1b79..685ec3c7 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -471,7 +471,6 @@ void Thread::YieldCPU() {
class FreeBSDMutex : public Mutex {
public:
-
FreeBSDMutex() {
pthread_mutexattr_t attrs;
int result = pthread_mutexattr_init(&attrs);
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 362bf47c..b152dae9 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -130,13 +130,7 @@ void OS::Setup() {
uint64_t OS::CpuFeaturesImpliedByPlatform() {
-#if(defined(__mips_hard_float) && __mips_hard_float != 0)
- // Here gcc is telling us that we are on an MIPS and gcc is assuming that we
- // have FPU instructions. If gcc can assume it then so can we.
- return 1u << FPU;
-#else
return 0; // Linux runs on anything.
-#endif
}
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index be6e1572..6be941a0 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -558,7 +558,6 @@ void Thread::YieldCPU() {
class MacOSMutex : public Mutex {
public:
-
MacOSMutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 1e79f102..035d3944 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -460,7 +460,6 @@ void Thread::YieldCPU() {
class SolarisMutex : public Mutex {
public:
-
SolarisMutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index e5df5ff3..97788e2f 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -35,76 +35,8 @@
#include "platform.h"
#include "vm-state-inl.h"
-// Extra POSIX/ANSI routines for Win32 when when using Visual Studio C++. Please
-// refer to The Open Group Base Specification for specification of the correct
-// semantics for these functions.
-// (http://www.opengroup.org/onlinepubs/000095399/)
#ifdef _MSC_VER
-namespace v8 {
-namespace internal {
-
-// Test for finite value - usually defined in math.h
-int isfinite(double x) {
- return _finite(x);
-}
-
-} // namespace v8
-} // namespace internal
-
-// Test for a NaN (not a number) value - usually defined in math.h
-int isnan(double x) {
- return _isnan(x);
-}
-
-
-// Test for infinity - usually defined in math.h
-int isinf(double x) {
- return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
-}
-
-
-// Test if x is less than y and both nominal - usually defined in math.h
-int isless(double x, double y) {
- return isnan(x) || isnan(y) ? 0 : x < y;
-}
-
-
-// Test if x is greater than y and both nominal - usually defined in math.h
-int isgreater(double x, double y) {
- return isnan(x) || isnan(y) ? 0 : x > y;
-}
-
-
-// Classify floating point number - usually defined in math.h
-int fpclassify(double x) {
- // Use the MS-specific _fpclass() for classification.
- int flags = _fpclass(x);
-
- // Determine class. We cannot use a switch statement because
- // the _FPCLASS_ constants are defined as flags.
- if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
- if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
- if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
- if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
-
- // All cases should be covered by the code above.
- ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
- return FP_NAN;
-}
-
-
-// Test sign - usually defined in math.h
-int signbit(double x) {
- // We need to take care of the special case of both positive
- // and negative versions of zero.
- if (x == 0)
- return _fpclass(x) & _FPCLASS_NZ;
- else
- return x < 0;
-}
-
-
// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
// defined in strings.h.
int strncasecmp(const char* s1, const char* s2, int n) {
@@ -1367,7 +1299,7 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
// Try to locate a symbol for this frame.
DWORD64 symbol_displacement;
- SmartPointer<IMAGEHLP_SYMBOL64> symbol(
+ SmartArrayPointer<IMAGEHLP_SYMBOL64> symbol(
NewArray<IMAGEHLP_SYMBOL64>(kStackWalkMaxNameLen));
if (symbol.is_empty()) return kStackWalkError; // Out of memory.
memset(*symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + kStackWalkMaxNameLen);
diff --git a/src/platform.h b/src/platform.h
index 6b2348c8..034fe340 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -44,7 +44,22 @@
#ifndef V8_PLATFORM_H_
#define V8_PLATFORM_H_
-#define V8_INFINITY INFINITY
+#ifdef __sun
+# ifndef signbit
+int signbit(double x);
+# endif
+#endif
+
+// GCC specific stuff
+#ifdef __GNUC__
+
+// Needed for va_list on at least MinGW and Android.
+#include <stdarg.h>
+
+#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
+
+#endif // __GNUC__
+
// Windows specific stuff.
#ifdef WIN32
@@ -52,27 +67,7 @@
// Microsoft Visual C++ specific stuff.
#ifdef _MSC_VER
-enum {
- FP_NAN,
- FP_INFINITE,
- FP_ZERO,
- FP_SUBNORMAL,
- FP_NORMAL
-};
-
-#undef V8_INFINITY
-#define V8_INFINITY HUGE_VAL
-
-namespace v8 {
-namespace internal {
-int isfinite(double x);
-} }
-int isnan(double x);
-int isinf(double x);
-int isless(double x, double y);
-int isgreater(double x, double y);
-int fpclassify(double x);
-int signbit(double x);
+#include "win32-math.h"
int strncasecmp(const char* s1, const char* s2, int n);
@@ -83,36 +78,6 @@ int random();
#endif // WIN32
-
-#ifdef __sun
-# ifndef signbit
-int signbit(double x);
-# endif
-#endif
-
-
-// GCC specific stuff
-#ifdef __GNUC__
-
-// Needed for va_list on at least MinGW and Android.
-#include <stdarg.h>
-
-#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
-
-// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
-// warning flag and certain versions of GCC due to a bug:
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
-// For now, we use the more involved template-based version from <limits>, but
-// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
-// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
-#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100
-#include <limits>
-#undef V8_INFINITY
-#define V8_INFINITY std::numeric_limits<double>::infinity()
-#endif
-
-#endif // __GNUC__
-
#include "atomicops.h"
#include "platform-tls.h"
#include "utils.h"
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 80656d5d..899489e2 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -25,15 +25,19 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifdef _MSC_VER
+#define V8_WIN32_LEAN_AND_MEAN
+#include "win32-headers.h"
+#endif
+
#include "../include/v8-preparser.h"
#include "globals.h"
-#include "flags.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
#include "list.h"
-#include "scanner-base.h"
+#include "hashmap.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "preparser.h"
diff --git a/src/preparser.cc b/src/preparser.cc
index 1a3dd737..47d21bac 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -25,22 +25,31 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <math.h>
+
#include "../include/v8stdint.h"
-#include "unicode.h"
-#include "globals.h"
-#include "checks.h"
+
#include "allocation.h"
-#include "utils.h"
+#include "checks.h"
+#include "conversions.h"
+#include "conversions-inl.h"
+#include "globals.h"
+#include "hashmap.h"
#include "list.h"
-
-#include "scanner-base.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "preparser.h"
-
-#include "conversions-inl.h"
+#include "unicode.h"
+#include "utils.h"
namespace v8 {
+
+#ifdef _MSC_VER
+// Usually defined in math.h, but not in MSVC.
+// Abstracted to work
+int isfinite(double value);
+#endif
+
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
@@ -68,27 +77,22 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
// Four of the tokens are treated specially
switch (token) {
case i::Token::EOS:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_eos", NULL);
+ return ReportMessageAt(source_location, "unexpected_eos", NULL);
case i::Token::NUMBER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_number", NULL);
+ return ReportMessageAt(source_location, "unexpected_token_number", NULL);
case i::Token::STRING:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_string", NULL);
+ return ReportMessageAt(source_location, "unexpected_token_string", NULL);
case i::Token::IDENTIFIER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ return ReportMessageAt(source_location,
"unexpected_token_identifier", NULL);
case i::Token::FUTURE_RESERVED_WORD:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_reserved", NULL);
+ return ReportMessageAt(source_location, "unexpected_reserved", NULL);
case i::Token::FUTURE_STRICT_RESERVED_WORD:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ return ReportMessageAt(source_location,
"unexpected_strict_reserved", NULL);
default:
const char* name = i::Token::String(token);
- ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token", name);
+ ReportMessageAt(source_location, "unexpected_token", name);
}
}
@@ -98,7 +102,7 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
i::Scanner::Location octal = scanner_->octal_position();
if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
- ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL);
+ ReportMessageAt(octal, "strict_octal_literal", NULL);
scanner_->clear_octal_position();
*ok = false;
}
@@ -251,7 +255,7 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
if (identifier.IsFutureStrictReserved()) {
type = "strict_reserved_word";
}
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
}
return Statement::FunctionDeclaration();
@@ -313,8 +317,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
} else if (peek() == i::Token::CONST) {
if (strict_mode()) {
i::Scanner::Location location = scanner_->peek_location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_const", NULL);
+ ReportMessageAt(location, "strict_const", NULL);
*ok = false;
return Statement::Default();
}
@@ -475,8 +478,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
Expect(i::Token::WITH, CHECK_OK);
if (strict_mode()) {
i::Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_mode_with", NULL);
+ ReportMessageAt(location, "strict_mode_with", NULL);
*ok = false;
return Statement::Default();
}
@@ -612,8 +614,7 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
Expect(i::Token::THROW, CHECK_OK);
if (scanner_->HasAnyLineTerminatorBeforeNext()) {
i::JavaScriptScanner::Location pos = scanner_->location();
- ReportMessageAt(pos.beg_pos, pos.end_pos,
- "newline_after_throw", NULL);
+ ReportMessageAt(pos, "newline_after_throw", NULL);
*ok = false;
return Statement::Default();
}
@@ -1025,8 +1026,7 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
if (strict_mode()) {
Next();
i::Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_reserved_word", NULL);
+ ReportMessageAt(location, "strict_reserved_word", NULL);
*ok = false;
return Expression::Default();
}
@@ -1107,6 +1107,39 @@ PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
return Expression::Default();
}
+void PreParser::CheckDuplicate(DuplicateFinder* finder,
+ i::Token::Value property,
+ int type,
+ bool* ok) {
+ int old_type;
+ if (property == i::Token::NUMBER) {
+ old_type = finder->AddNumber(scanner_->literal_ascii_string(), type);
+ } else if (scanner_->is_literal_ascii()) {
+ old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
+ type);
+ } else {
+ old_type = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type);
+ }
+ if (HasConflict(old_type, type)) {
+ if (IsDataDataConflict(old_type, type)) {
+ // Both are data properties.
+ if (!strict_mode()) return;
+ ReportMessageAt(scanner_->location(),
+ "strict_duplicate_property", NULL);
+ } else if (IsDataAccessorConflict(old_type, type)) {
+ // Both a data and an accessor property with the same name.
+ ReportMessageAt(scanner_->location(),
+ "accessor_data_property", NULL);
+ } else {
+ ASSERT(IsAccessorAccessorConflict(old_type, type));
+ // Both accessors of the same type.
+ ReportMessageAt(scanner_->location(),
+ "accessor_get_set", NULL);
+ }
+ *ok = false;
+ }
+}
+
PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
// ObjectLiteral ::
@@ -1116,6 +1149,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
// )*[','] '}'
Expect(i::Token::LBRACE, CHECK_OK);
+ DuplicateFinder duplicate_finder(scanner_->unicode_cache());
while (peek() != i::Token::RBRACE) {
i::Token::Value next = peek();
switch (next) {
@@ -1140,24 +1174,30 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
if (!is_keyword) {
LogSymbol();
}
+ PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
+ CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
ParseFunctionLiteral(CHECK_OK);
if (peek() != i::Token::RBRACE) {
Expect(i::Token::COMMA, CHECK_OK);
}
continue; // restart the while
}
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
break;
}
case i::Token::STRING:
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
GetStringSymbol();
break;
case i::Token::NUMBER:
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
break;
default:
if (i::Token::IsKeyword(next)) {
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
} else {
// Unexpected token.
*ok = false;
@@ -1182,9 +1222,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
bool* ok) {
if (!scanner_->ScanRegExpPattern(seen_equal)) {
Next();
- i::JavaScriptScanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "unterminated_regexp", NULL);
+ ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
*ok = false;
return Expression::Default();
}
@@ -1193,9 +1231,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
if (!scanner_->ScanRegExpFlags()) {
Next();
- i::JavaScriptScanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "invalid_regexp_flags", NULL);
+ ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
*ok = false;
return Expression::Default();
}
@@ -1240,6 +1276,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
Expect(i::Token::LPAREN, CHECK_OK);
int start_position = scanner_->location().beg_pos;
bool done = (peek() == i::Token::RPAREN);
+ DuplicateFinder duplicate_finder(scanner_->unicode_cache());
while (!done) {
Identifier id = ParseIdentifier(CHECK_OK);
if (!id.IsValidStrictVariable()) {
@@ -1248,6 +1285,20 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
id,
CHECK_OK);
}
+ int prev_value;
+ if (scanner_->is_literal_ascii()) {
+ prev_value =
+ duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
+ } else {
+ prev_value =
+ duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1);
+ }
+
+ if (prev_value != 0) {
+ SetStrictModeViolation(scanner_->location(),
+ "strict_param_dupe",
+ CHECK_OK);
+ }
done = (peek() == i::Token::RPAREN);
if (!done) {
Expect(i::Token::COMMA, CHECK_OK);
@@ -1399,13 +1450,18 @@ void PreParser::SetStrictModeViolation(i::Scanner::Location location,
const char* type,
bool* ok) {
if (strict_mode()) {
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
return;
}
// Delay report in case this later turns out to be strict code
// (i.e., for function names and parameters prior to a "use strict"
// directive).
+ // It's safe to overwrite an existing violation.
+ // It's either from a function that turned out to be non-strict,
+ // or it's in the current function (and we just need to report
+ // one error), or it's in a unclosed nesting function that wasn't
+ // strict (otherwise we would already be in strict mode).
strict_mode_violation_location_ = location;
strict_mode_violation_type_ = type;
}
@@ -1417,11 +1473,9 @@ void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
i::Scanner::Location location = strict_mode_violation_location_;
if (location.IsValid() &&
location.beg_pos > beg_pos && location.end_pos < end_pos) {
- ReportMessageAt(location.beg_pos, location.end_pos,
- strict_mode_violation_type_, NULL);
+ ReportMessageAt(location, strict_mode_violation_type_, NULL);
*ok = false;
}
- strict_mode_violation_location_ = i::Scanner::Location::invalid();
}
@@ -1436,7 +1490,7 @@ void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
type = "strict_reserved_word";
}
if (strict_mode()) {
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
return;
}
@@ -1488,4 +1542,138 @@ bool PreParser::peek_any_identifier() {
next == i::Token::FUTURE_RESERVED_WORD ||
next == i::Token::FUTURE_STRICT_RESERVED_WORD;
}
+
+
+int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) {
+ return AddSymbol(i::Vector<const byte>::cast(key), true, value);
+}
+
+int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) {
+ return AddSymbol(i::Vector<const byte>::cast(key), false, value);
+}
+
+int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
+ bool is_ascii,
+ int value) {
+ uint32_t hash = Hash(key, is_ascii);
+ byte* encoding = BackupKey(key, is_ascii);
+ i::HashMap::Entry* entry = map_.Lookup(encoding, hash, true);
+ int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+ entry->value =
+ reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
+ return old_value;
+}
+
+
+int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) {
+ ASSERT(key.length() > 0);
+ // Quick check for already being in canonical form.
+ if (IsNumberCanonical(key)) {
+ return AddAsciiSymbol(key, value);
+ }
+
+ int flags = i::ALLOW_HEX | i::ALLOW_OCTALS;
+ double double_value = StringToDouble(unicode_constants_, key, flags, 0.0);
+ int length;
+ const char* string;
+ if (!isfinite(double_value)) {
+ string = "Infinity";
+ length = 8; // strlen("Infinity");
+ } else {
+ string = DoubleToCString(double_value,
+ i::Vector<char>(number_buffer_, kBufferSize));
+ length = i::StrLength(string);
+ }
+ return AddSymbol(i::Vector<const byte>(reinterpret_cast<const byte*>(string),
+ length), true, value);
+}
+
+
+bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
+ // Test for a safe approximation of number literals that are already
+ // in canonical form: max 15 digits, no leading zeroes, except an
+ // integer part that is a single zero, and no trailing zeros below
+ // the decimal point.
+ int pos = 0;
+ int length = number.length();
+ if (number.length() > 15) return false;
+ if (number[pos] == '0') {
+ pos++;
+ } else {
+ while (pos < length &&
+ static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
+ }
+ if (length == pos) return true;
+ if (number[pos] != '.') return false;
+ pos++;
+ bool invalid_last_digit = true;
+ while (pos < length) {
+ byte digit = number[pos] - '0';
+ if (digit > '9' - '0') return false;
+ invalid_last_digit = (digit == 0);
+ pos++;
+ }
+ return !invalid_last_digit;
+}
+
+
+uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
+ // Primitive hash function, almost identical to the one used
+ // for strings (except that it's seeded by the length and ASCII-ness).
+ int length = key.length();
+ uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
+ for (int i = 0; i < length; i++) {
+ uint32_t c = key[i];
+ hash = (hash + c) * 1025;
+ hash ^= (hash >> 6);
+ }
+ return hash;
+}
+
+
+bool DuplicateFinder::Match(void* first, void* second) {
+ // Decode lengths.
+ // Length + ASCII-bit is encoded as base 128, most significant heptet first,
+ // with a 8th bit being non-zero while there are more heptets.
+ // The value encodes the number of bytes following, and whether the original
+ // was ASCII.
+ byte* s1 = reinterpret_cast<byte*>(first);
+ byte* s2 = reinterpret_cast<byte*>(second);
+ uint32_t length_ascii_field = 0;
+ byte c1;
+ do {
+ c1 = *s1;
+ if (c1 != *s2) return false;
+ length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
+ s1++;
+ s2++;
+ } while ((c1 & 0x80) != 0);
+ int length = static_cast<int>(length_ascii_field >> 1);
+ return memcmp(s1, s2, length) == 0;
+}
+
+
+byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
+ bool is_ascii) {
+ uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
+ backing_store_.StartSequence();
+ // Emit ascii_length as base-128 encoded number, with the 7th bit set
+ // on the byte of every heptet except the last, least significant, one.
+ if (ascii_length >= (1 << 7)) {
+ if (ascii_length >= (1 << 14)) {
+ if (ascii_length >= (1 << 21)) {
+ if (ascii_length >= (1 << 28)) {
+ backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
+
+ backing_store_.AddBlock(bytes);
+ return backing_store_.EndSequence().start();
+}
} } // v8::preparser
diff --git a/src/preparser.h b/src/preparser.h
index cd0a530e..b97b7cff 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -28,9 +28,19 @@
#ifndef V8_PREPARSER_H
#define V8_PREPARSER_H
+#include "token.h"
+#include "scanner.h"
+
namespace v8 {
+
+namespace internal {
+class UnicodeCache;
+}
+
namespace preparser {
+typedef uint8_t byte;
+
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// See preparse-data-format.h for the data format.
@@ -46,6 +56,53 @@ namespace preparser {
namespace i = v8::internal;
+class DuplicateFinder {
+ public:
+ explicit DuplicateFinder(i::UnicodeCache* constants)
+ : unicode_constants_(constants),
+ backing_store_(16),
+ map_(&Match) { }
+
+ int AddAsciiSymbol(i::Vector<const char> key, int value);
+ int AddUC16Symbol(i::Vector<const uint16_t> key, int value);
+ // Add a a number literal by converting it (if necessary)
+ // to the string that ToString(ToNumber(literal)) would generate.
+ // and then adding that string with AddAsciiSymbol.
+ // This string is the actual value used as key in an object literal,
+ // and the one that must be different from the other keys.
+ int AddNumber(i::Vector<const char> key, int value);
+
+ private:
+ int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value);
+ // Backs up the key and its length in the backing store.
+ // The backup is stored with a base 127 encoding of the
+ // length (plus a bit saying whether the string is ASCII),
+ // followed by the bytes of the key.
+ byte* BackupKey(i::Vector<const byte> key, bool is_ascii);
+
+ // Compare two encoded keys (both pointing into the backing store)
+ // for having the same base-127 encoded lengths and ASCII-ness,
+ // and then having the same 'length' bytes following.
+ static bool Match(void* first, void* second);
+ // Creates a hash from a sequence of bytes.
+ static uint32_t Hash(i::Vector<const byte> key, bool is_ascii);
+ // Checks whether a string containing a JS number is its canonical
+ // form.
+ static bool IsNumberCanonical(i::Vector<const char> key);
+
+ // Size of buffer. Sufficient for using it to call DoubleToCString in
+ // from conversions.h.
+ static const int kBufferSize = 100;
+
+ i::UnicodeCache* unicode_constants_;
+ // Backing store used to store strings used as hashmap keys.
+ i::SequenceCollector<unsigned char> backing_store_;
+ i::HashMap map_;
+ // Buffer used for string->number->canonical string conversions.
+ char number_buffer_[kBufferSize];
+};
+
+
class PreParser {
public:
enum PreParseResult {
@@ -53,7 +110,7 @@ class PreParser {
kPreParseSuccess
};
- ~PreParser() { }
+ ~PreParser() {}
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
@@ -67,6 +124,45 @@ class PreParser {
}
private:
+ // Used to detect duplicates in object literals. Each of the values
+ // kGetterProperty, kSetterProperty and kValueProperty represents
+ // a type of object literal property. When parsing a property, its
+ // type value is stored in the DuplicateFinder for the property name.
+ // Values are chosen so that having intersection bits means the there is
+ // an incompatibility.
+ // I.e., you can add a getter to a property that already has a setter, since
+ // kGetterProperty and kSetterProperty doesn't intersect, but not if it
+ // already has a getter or a value. Adding the getter to an existing
+ // setter will store the value (kGetterProperty | kSetterProperty), which
+ // is incompatible with adding any further properties.
+ enum PropertyType {
+ kNone = 0,
+ // Bit patterns representing different object literal property types.
+ kGetterProperty = 1,
+ kSetterProperty = 2,
+ kValueProperty = 7,
+ // Helper constants.
+ kValueFlag = 4
+ };
+
+ // Checks the type of conflict based on values coming from PropertyType.
+ bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; }
+ bool IsDataDataConflict(int type1, int type2) {
+ return ((type1 & type2) & kValueFlag) != 0;
+ }
+ bool IsDataAccessorConflict(int type1, int type2) {
+ return ((type1 ^ type2) & kValueFlag) != 0;
+ }
+ bool IsAccessorAccessorConflict(int type1, int type2) {
+ return ((type1 | type2) & kValueFlag) == 0;
+ }
+
+
+ void CheckDuplicate(DuplicateFinder* finder,
+ i::Token::Value property,
+ int type,
+ bool* ok);
+
// These types form an algebra over syntactic categories that is just
// rich enough to let us recognize and propagate the constructs that
// are either being counted in the preparser data, or is important
@@ -371,6 +467,11 @@ class PreParser {
// Report syntax error
void ReportUnexpectedToken(i::Token::Value token);
+ void ReportMessageAt(i::Scanner::Location location,
+ const char* type,
+ const char* name_opt) {
+ log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
+ }
void ReportMessageAt(int start_pos,
int end_pos,
const char* type,
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index b0342934..663af284 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -131,11 +131,6 @@ void PrettyPrinter::VisitWithStatement(WithStatement* node) {
}
-void PrettyPrinter::VisitExitContextStatement(ExitContextStatement* node) {
- Print("<exit context>");
-}
-
-
void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
PrintLabels(node->labels());
Print("switch (");
@@ -284,28 +279,6 @@ void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
}
-void PrettyPrinter::VisitSlot(Slot* node) {
- switch (node->type()) {
- case Slot::PARAMETER:
- Print("parameter[%d]", node->index());
- break;
- case Slot::LOCAL:
- Print("local[%d]", node->index());
- break;
- case Slot::CONTEXT:
- Print("context[%d]", node->index());
- break;
- case Slot::LOOKUP:
- Print("lookup[");
- PrintLiteral(node->var()->name(), false);
- Print("]");
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteral(node->name(), false);
}
@@ -660,17 +633,14 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
void AstPrinter::PrintLabelsIndented(const char* info, ZoneStringList* labels) {
if (labels != NULL && labels->length() > 0) {
- if (info == NULL) {
- PrintIndented("LABELS ");
- } else {
- PrintIndented(info);
- Print(" ");
- }
+ PrintIndented(info == NULL ? "LABELS" : info);
+ Print(" ");
PrintLabels(labels);
+ Print("\n");
} else if (info != NULL) {
PrintIndented(info);
+ Print("\n");
}
- Print("\n");
}
@@ -751,7 +721,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
if (node->fun() == NULL) {
// var or const declarations
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
- node->proxy()->AsVariable(),
+ node->proxy()->var(),
node->proxy()->name());
} else {
// function declarations
@@ -805,11 +775,6 @@ void AstPrinter::VisitWithStatement(WithStatement* node) {
}
-void AstPrinter::VisitExitContextStatement(ExitContextStatement* node) {
- PrintIndented("EXIT CONTEXT\n");
-}
-
-
void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
IndentedScope indent(this, "SWITCH");
PrintLabelsIndented(NULL, node->labels());
@@ -959,20 +924,27 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
}
-void AstPrinter::VisitSlot(Slot* node) {
- PrintIndented("SLOT ");
- PrettyPrinter::VisitSlot(node);
- Print("\n");
-}
-
-
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
- PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name());
Variable* var = node->var();
- if (var != NULL && var->rewrite() != NULL) {
- IndentedScope indent(this);
- Visit(var->rewrite());
+ EmbeddedVector<char, 128> buf;
+ int pos = OS::SNPrintF(buf, "VAR PROXY");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ break;
+ case Variable::PARAMETER:
+ OS::SNPrintF(buf + pos, " parameter[%d]", var->index());
+ break;
+ case Variable::LOCAL:
+ OS::SNPrintF(buf + pos, " local[%d]", var->index());
+ break;
+ case Variable::CONTEXT:
+ OS::SNPrintF(buf + pos, " context[%d]", var->index());
+ break;
+ case Variable::LOOKUP:
+ OS::SNPrintF(buf + pos, " lookup");
+ break;
}
+ PrintLiteralWithModeIndented(buf.start(), var, node->name());
}
@@ -1130,7 +1102,7 @@ void JsonAstBuilder::AddAttributePrefix(const char* name) {
void JsonAstBuilder::AddAttribute(const char* name, Handle<String> value) {
- SmartPointer<char> value_string = value->ToCString();
+ SmartArrayPointer<char> value_string = value->ToCString();
AddAttributePrefix(name);
Print("\"%s\"", *value_string);
}
@@ -1202,11 +1174,6 @@ void JsonAstBuilder::VisitWithStatement(WithStatement* stmt) {
}
-void JsonAstBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
- TagScope tag(this, "ExitContextStatement");
-}
-
-
void JsonAstBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
TagScope tag(this, "SwitchStatement");
}
@@ -1287,39 +1254,32 @@ void JsonAstBuilder::VisitConditional(Conditional* expr) {
}
-void JsonAstBuilder::VisitSlot(Slot* expr) {
- TagScope tag(this, "Slot");
+void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
+ TagScope tag(this, "Variable");
{
AttributesScope attributes(this);
- switch (expr->type()) {
- case Slot::PARAMETER:
- AddAttribute("type", "PARAMETER");
+ Variable* var = expr->var();
+ AddAttribute("name", var->name());
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ AddAttribute("location", "UNALLOCATED");
break;
- case Slot::LOCAL:
- AddAttribute("type", "LOCAL");
+ case Variable::PARAMETER:
+ AddAttribute("location", "PARAMETER");
+ AddAttribute("index", var->index());
break;
- case Slot::CONTEXT:
- AddAttribute("type", "CONTEXT");
+ case Variable::LOCAL:
+ AddAttribute("location", "LOCAL");
+ AddAttribute("index", var->index());
break;
- case Slot::LOOKUP:
- AddAttribute("type", "LOOKUP");
+ case Variable::CONTEXT:
+ AddAttribute("location", "CONTEXT");
+ AddAttribute("index", var->index());
+ break;
+ case Variable::LOOKUP:
+ AddAttribute("location", "LOOKUP");
break;
}
- AddAttribute("index", expr->index());
- }
-}
-
-
-void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
- if (expr->var()->rewrite() == NULL) {
- TagScope tag(this, "VariableProxy");
- {
- AttributesScope attributes(this);
- AddAttribute("name", expr->name());
- AddAttribute("mode", Variable::Mode2String(expr->var()->mode()));
- }
- } else {
- Visit(expr->var()->rewrite());
}
}
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index 080081dd..a26c48e4 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -52,7 +52,6 @@ class PrettyPrinter: public AstVisitor {
// Print a node to stdout.
static void PrintOut(AstNode* node);
- virtual void VisitSlot(Slot* node);
// Individual nodes
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
@@ -87,7 +86,6 @@ class AstPrinter: public PrettyPrinter {
const char* PrintProgram(FunctionLiteral* program);
// Individual nodes
- virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
@@ -163,7 +161,6 @@ class JsonAstBuilder: public PrettyPrinter {
void AddAttribute(const char* name, bool value);
// AST node visit functions.
- virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 8f4bc6c1..88d6e879 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -78,22 +78,6 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry)
}
-void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
- CodeTree::Locator locator;
- tree_.Insert(addr, &locator);
- locator.set_value(CodeEntryInfo(entry, size));
-}
-
-
-void CodeMap::MoveCode(Address from, Address to) {
- tree_.Move(from, to);
-}
-
-void CodeMap::DeleteCode(Address addr) {
- tree_.Remove(addr);
-}
-
-
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 5a95445d..adf55ad2 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -492,6 +492,28 @@ const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
CodeMap::CodeEntryInfo(NULL, 0);
+void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
+ DeleteAllCoveredCode(addr, addr + size);
+ CodeTree::Locator locator;
+ tree_.Insert(addr, &locator);
+ locator.set_value(CodeEntryInfo(entry, size));
+}
+
+
+void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+ List<Address> to_delete;
+ Address addr = end - 1;
+ while (addr >= start) {
+ CodeTree::Locator locator;
+ if (!tree_.FindGreatestLessThan(addr, &locator)) break;
+ Address start2 = locator.key(), end2 = start2 + locator.value().size;
+ if (start2 < end && start < end2) to_delete.Add(start2);
+ addr = start2 - 1;
+ }
+ for (int i = 0; i < to_delete.length(); ++i) tree_.Remove(to_delete[i]);
+}
+
+
CodeEntry* CodeMap::FindEntry(Address addr) {
CodeTree::Locator locator;
if (tree_.FindGreatestLessThan(addr, &locator)) {
@@ -520,6 +542,16 @@ int CodeMap::GetSharedId(Address addr) {
}
+void CodeMap::MoveCode(Address from, Address to) {
+ if (from == to) return;
+ CodeTree::Locator locator;
+ if (!tree_.Find(from, &locator)) return;
+ CodeEntryInfo entry = locator.value();
+ tree_.Remove(from);
+ AddCode(to, entry.entry, entry.size);
+}
+
+
void CodeMap::CodeTreePrinter::Call(
const Address& key, const CodeMap::CodeEntryInfo& value) {
OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
diff --git a/src/profile-generator.h b/src/profile-generator.h
index fbb6fab2..da1fdc33 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -238,9 +238,8 @@ class CpuProfile {
class CodeMap {
public:
CodeMap() : next_shared_id_(1) { }
- INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
- INLINE(void MoveCode(Address from, Address to));
- INLINE(void DeleteCode(Address addr));
+ void AddCode(Address addr, CodeEntry* entry, unsigned size);
+ void MoveCode(Address from, Address to);
CodeEntry* FindEntry(Address addr);
int GetSharedId(Address addr);
@@ -270,6 +269,8 @@ class CodeMap {
void Call(const Address& key, const CodeEntryInfo& value);
};
+ void DeleteAllCoveredCode(Address start, Address end);
+
// Fake CodeEntry pointer to distinguish shared function entries.
static CodeEntry* const kSharedFunctionCodeEntry;
diff --git a/src/property.cc b/src/property.cc
index dd232093..7cc2df5a 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -52,8 +52,8 @@ void LookupResult::Print(FILE* out) {
GetTransitionMap()->Print(out);
PrintF(out, "\n");
break;
- case EXTERNAL_ARRAY_TRANSITION:
- PrintF(out, " -type = external array transition\n");
+ case ELEMENTS_TRANSITION:
+ PrintF(out, " -type = elements transition\n");
PrintF(out, " -map:\n");
GetTransitionMap()->Print(out);
PrintF(out, "\n");
diff --git a/src/property.h b/src/property.h
index ddecc921..e7d9fc53 100644
--- a/src/property.h
+++ b/src/property.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -112,14 +112,14 @@ class MapTransitionDescriptor: public Descriptor {
: Descriptor(key, map, attributes, MAP_TRANSITION) { }
};
-class ExternalArrayTransitionDescriptor: public Descriptor {
+class ElementsTransitionDescriptor: public Descriptor {
public:
- ExternalArrayTransitionDescriptor(String* key,
- Map* map,
- ExternalArrayType array_type)
+ ElementsTransitionDescriptor(String* key,
+ Map* map,
+ ElementsKind elements_kind)
: Descriptor(key, map, PropertyDetails(NONE,
- EXTERNAL_ARRAY_TRANSITION,
- array_type)) { }
+ ELEMENTS_TRANSITION,
+ elements_kind)) { }
};
// Marks a field name in a map so that adding the field is guaranteed
@@ -281,7 +281,7 @@ class LookupResult BASE_EMBEDDED {
Map* GetTransitionMap() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION ||
- type() == EXTERNAL_ARRAY_TRANSITION);
+ type() == ELEMENTS_TRANSITION);
return Map::cast(GetValue());
}
diff --git a/src/proxy.js b/src/proxy.js
index 28391595..4e44cd4e 100644
--- a/src/proxy.js
+++ b/src/proxy.js
@@ -29,36 +29,6 @@ global.Proxy = new $Object();
var $Proxy = global.Proxy
-var fundamentalTraps = [
- "getOwnPropertyDescriptor",
- "getPropertyDescriptor",
- "getOwnPropertyNames",
- "getPropertyNames",
- "defineProperty",
- "delete",
- "fix",
-]
-
-var derivedTraps = [
- "has",
- "hasOwn",
- "get",
- "set",
- "enumerate",
- "keys",
-]
-
-var functionTraps = [
- "callTrap",
- "constructTrap",
-]
-
-$Proxy.createFunction = function(handler, callTrap, constructTrap) {
- handler.callTrap = callTrap
- handler.constructTrap = constructTrap
- $Proxy.create(handler)
-}
-
$Proxy.create = function(handler, proto) {
if (!IS_SPEC_OBJECT(handler))
throw MakeTypeError("handler_non_object", ["create"])
@@ -66,6 +36,20 @@ $Proxy.create = function(handler, proto) {
return %CreateJSProxy(handler, proto)
}
+$Proxy.createFunction = function(handler, callTrap, constructTrap) {
+ if (!IS_SPEC_OBJECT(handler))
+ throw MakeTypeError("handler_non_object", ["create"])
+ if (!IS_SPEC_FUNCTION(callTrap))
+ throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
+ if (IS_UNDEFINED(constructTrap)) {
+ constructTrap = callTrap
+ } else if (!IS_SPEC_FUNCTION(constructTrap)) {
+ throw MakeTypeError("trap_function_expected",
+ ["createFunction", "construct"])
+ }
+ return %CreateJSFunctionProxy(
+ handler, callTrap, constructTrap, $Function.prototype)
+}
@@ -73,6 +57,13 @@ $Proxy.create = function(handler, proto) {
// Builtins
////////////////////////////////////////////////////////////////////////////////
+function DelegateCallAndConstruct(callTrap, constructTrap) {
+ return function() {
+ return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
+ this, arguments, 0, %_ArgumentsLength())
+ }
+}
+
function DerivedGetTrap(receiver, name) {
var desc = this.getPropertyDescriptor(name)
if (IS_UNDEFINED(desc)) { return desc }
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
index 75cf8bf9..262ead29 100644
--- a/src/regexp-macro-assembler-irregexp.h
+++ b/src/regexp-macro-assembler-irregexp.h
@@ -107,6 +107,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
virtual IrregexpImplementation Implementation();
virtual Handle<HeapObject> GetCode(Handle<String> source);
+
private:
void Expand();
// Code and bitmap emission.
diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h
index 8c6cf3ab..1cf0349d 100644
--- a/src/regexp-macro-assembler-tracer.h
+++ b/src/regexp-macro-assembler-tracer.h
@@ -95,6 +95,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
virtual void ClearRegisters(int reg_from, int reg_to);
virtual void WriteStackPointerToRegister(int reg);
+
private:
RegExpMacroAssembler* assembler_;
};
diff --git a/src/regexp-stack.h b/src/regexp-stack.h
index 59432067..5684239f 100644
--- a/src/regexp-stack.h
+++ b/src/regexp-stack.h
@@ -89,6 +89,7 @@ class RegExpStack {
char* ArchiveStack(char* to);
char* RestoreStack(char* from);
void FreeThreadResources() { thread_local_.Free(); }
+
private:
RegExpStack();
~RegExpStack();
diff --git a/src/regexp.js b/src/regexp.js
index a7f42d59..38d44961 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -405,7 +405,8 @@ var lastMatchInfoOverride = null;
// -------------------------------------------------------------------
-function SetupRegExp() {
+function SetUpRegExp() {
+ %CheckIsBootstrapping();
%FunctionSetInstanceClassName($RegExp, 'RegExp');
%FunctionSetPrototype($RegExp, new $Object());
%SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
@@ -484,5 +485,4 @@ function SetupRegExp() {
}
}
-
-SetupRegExp();
+SetUpRegExp();
diff --git a/src/rewriter.cc b/src/rewriter.cc
index ad6ce056..3d4c2dcc 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -208,7 +208,6 @@ void Processor::VisitWithStatement(WithStatement* node) {
void Processor::VisitDeclaration(Declaration* node) {}
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
void Processor::VisitReturnStatement(ReturnStatement* node) {}
-void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 917f6d0d..26d88461 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -115,10 +115,8 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
}
SharedFunctionInfo* shared = function->shared();
- // If the code is not optimizable or references context slots, don't try OSR.
- if (!shared->code()->optimizable() || !shared->allows_lazy_compilation()) {
- return;
- }
+ // If the code is not optimizable, don't try OSR.
+ if (!shared->code()->optimizable()) return;
// We are not prepared to do OSR for a function that already has an
// allocated arguments object. The optimized code would bypass it for
diff --git a/src/runtime.cc b/src/runtime.cc
index 50f9ce19..813f98f6 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -32,6 +32,7 @@
#include "accessors.h"
#include "api.h"
#include "arguments.h"
+#include "bootstrapper.h"
#include "codegen.h"
#include "compilation-cache.h"
#include "compiler.h"
@@ -51,7 +52,7 @@
#include "runtime-profiler.h"
#include "runtime.h"
#include "scopeinfo.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "string-search.h"
#include "stub-cache.h"
#include "v8threads.h"
@@ -176,7 +177,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
@@ -200,7 +201,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
NumberDictionary* element_dictionary = copy->element_dictionary();
int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
@@ -219,19 +220,19 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
}
break;
}
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
// No contained objects, nothing to do.
break;
}
@@ -612,6 +613,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
+ ASSERT(args.length() == 4);
+ Object* handler = args[0];
+ Object* call_trap = args[1];
+ Object* construct_trap = args[2];
+ Object* prototype = args[3];
+ Object* used_prototype =
+ prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
+ return isolate->heap()->AllocateJSFunctionProxy(
+ handler, call_trap, construct_trap, used_prototype);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
ASSERT(args.length() == 1);
Object* obj = args[0];
@@ -619,6 +633,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
+ ASSERT(args.length() == 1);
+ Object* obj = args[0];
+ return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSProxy, proxy, args[0]);
@@ -626,6 +647,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
+ return proxy->call_trap();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
+ return proxy->construct_trap();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSProxy, proxy, args[0]);
@@ -1149,22 +1184,14 @@ static Failure* ThrowRedeclarationError(Isolate* isolate,
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
- ASSERT(args.length() == 4);
+ ASSERT(args.length() == 3);
HandleScope scope(isolate);
Handle<GlobalObject> global = Handle<GlobalObject>(
isolate->context()->global());
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
- bool is_eval = args.smi_at(2) == 1;
- StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
- ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
-
- // Compute the property attributes. According to ECMA-262, section
- // 13, page 71, the property must be read-only and
- // non-deletable. However, neither SpiderMonkey nor KJS creates the
- // property as read-only, so we don't either.
- PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
+ CONVERT_SMI_ARG_CHECKED(flags, 2);
// Traverse the name/value pairs and set the properties.
int length = pairs->length();
@@ -1177,7 +1204,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
// assign to it when evaluating the assignment for "const x =
// <expr>" the initial value is the hole.
bool is_const_property = value->IsTheHole();
-
+ bool is_function_declaration = false;
if (value->IsUndefined() || is_const_property) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
@@ -1226,6 +1253,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
}
}
} else {
+ is_function_declaration = true;
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value);
@@ -1239,10 +1267,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
LookupResult lookup;
global->LocalLookup(*name, &lookup);
- PropertyAttributes attributes = is_const_property
- ? static_cast<PropertyAttributes>(base | READ_ONLY)
- : base;
-
// There's a local property that we need to overwrite because
// we're either declaring a function or there's an interceptor
// that claims the property is absent.
@@ -1257,6 +1281,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
return ThrowRedeclarationError(isolate, type, name);
}
+ // Compute the property attributes. According to ECMA-262, section
+ // 13, page 71, the property must be read-only and
+ // non-deletable. However, neither SpiderMonkey nor KJS creates the
+ // property as read-only, so we don't either.
+ int attr = NONE;
+ if ((flags & kDeclareGlobalsEvalFlag) == 0) {
+ attr |= DONT_DELETE;
+ }
+ bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
+ if (is_const_property || (is_native && is_function_declaration)) {
+ attr |= READ_ONLY;
+ }
+
// Safari does not allow the invocation of callback setters for
// function declarations. To mimic this behavior, we do not allow
// the invocation of setters for function values. This makes a
@@ -1267,20 +1304,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
if (value->IsJSFunction()) {
// Do not change DONT_DELETE to false from true.
if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
- attributes = static_cast<PropertyAttributes>(
- attributes | (lookup.GetAttributes() & DONT_DELETE));
+ attr |= lookup.GetAttributes() & DONT_DELETE;
}
+ PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
+
RETURN_IF_EMPTY_HANDLE(isolate,
SetLocalPropertyIgnoreAttributes(global,
name,
value,
attributes));
} else {
+ StrictModeFlag strict_mode =
+ ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
+ : kNonStrictMode;
RETURN_IF_EMPTY_HANDLE(isolate,
SetProperty(global,
name,
value,
- attributes,
+ static_cast<PropertyAttributes>(attr),
strict_mode));
}
}
@@ -2202,6 +2243,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
// are guaranteed to be in old space.
target->set_literals(*literals, SKIP_WRITE_BARRIER);
target->set_next_function_link(isolate->heap()->undefined_value());
+
+ if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
+ isolate->logger()->LogExistingFunction(
+ shared, Handle<Code>(shared->code()));
+ }
}
target->set_context(*context);
@@ -2499,7 +2545,7 @@ class ReplacementStringBuilder {
class CompiledReplacement {
public:
CompiledReplacement()
- : parts_(1), replacement_substrings_(0) {}
+ : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
void Compile(Handle<String> replacement,
int capture_count,
@@ -2515,6 +2561,10 @@ class CompiledReplacement {
return parts_.length();
}
+ bool simple_hint() {
+ return simple_hint_;
+ }
+
private:
enum PartType {
SUBJECT_PREFIX = 1,
@@ -2573,7 +2623,7 @@ class CompiledReplacement {
};
template<typename Char>
- static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
+ static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
Vector<Char> characters,
int capture_count,
int subject_length) {
@@ -2670,14 +2720,17 @@ class CompiledReplacement {
if (length > last) {
if (last == 0) {
parts->Add(ReplacementPart::ReplacementString());
+ return true;
} else {
parts->Add(ReplacementPart::ReplacementSubString(last, length));
}
}
+ return false;
}
ZoneList<ReplacementPart> parts_;
ZoneList<Handle<String> > replacement_substrings_;
+ bool simple_hint_;
};
@@ -2689,16 +2742,16 @@ void CompiledReplacement::Compile(Handle<String> replacement,
String::FlatContent content = replacement->GetFlatContent();
ASSERT(content.IsFlat());
if (content.IsAscii()) {
- ParseReplacementPattern(&parts_,
- content.ToAsciiVector(),
- capture_count,
- subject_length);
+ simple_hint_ = ParseReplacementPattern(&parts_,
+ content.ToAsciiVector(),
+ capture_count,
+ subject_length);
} else {
ASSERT(content.IsTwoByte());
- ParseReplacementPattern(&parts_,
- content.ToUC16Vector(),
- capture_count,
- subject_length);
+ simple_hint_ = ParseReplacementPattern(&parts_,
+ content.ToUC16Vector(),
+ capture_count,
+ subject_length);
}
}
Isolate* isolate = replacement->GetIsolate();
@@ -2761,6 +2814,170 @@ void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
}
+void FindAsciiStringIndices(Vector<const char> subject,
+ char pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ ASSERT(limit > 0);
+ // Collect indices of pattern in subject using memchr.
+ // Stop after finding at most limit values.
+ const char* subject_start = reinterpret_cast<const char*>(subject.start());
+ const char* subject_end = subject_start + subject.length();
+ const char* pos = subject_start;
+ while (limit > 0) {
+ pos = reinterpret_cast<const char*>(
+ memchr(pos, pattern, subject_end - pos));
+ if (pos == NULL) return;
+ indices->Add(static_cast<int>(pos - subject_start));
+ pos++;
+ limit--;
+ }
+}
+
+
+template <typename SubjectChar, typename PatternChar>
+void FindStringIndices(Isolate* isolate,
+ Vector<const SubjectChar> subject,
+ Vector<const PatternChar> pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ ASSERT(limit > 0);
+ // Collect indices of pattern in subject.
+ // Stop after finding at most limit values.
+ int pattern_length = pattern.length();
+ int index = 0;
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
+ while (limit > 0) {
+ index = search.Search(subject, index);
+ if (index < 0) return;
+ indices->Add(index);
+ index += pattern_length;
+ limit--;
+ }
+}
+
+
+void FindStringIndicesDispatch(Isolate* isolate,
+ String* subject,
+ String* pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ {
+ AssertNoAllocation no_gc;
+ String::FlatContent subject_content = subject->GetFlatContent();
+ String::FlatContent pattern_content = pattern->GetFlatContent();
+ ASSERT(subject_content.IsFlat());
+ ASSERT(pattern_content.IsFlat());
+ if (subject_content.IsAscii()) {
+ Vector<const char> subject_vector = subject_content.ToAsciiVector();
+ if (pattern_content.IsAscii()) {
+ Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
+ if (pattern_vector.length() == 1) {
+ FindAsciiStringIndices(subject_vector,
+ pattern_vector[0],
+ indices,
+ limit);
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_vector,
+ indices,
+ limit);
+ }
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToUC16Vector(),
+ indices,
+ limit);
+ }
+ } else {
+ Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
+ if (pattern->IsAsciiRepresentation()) {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToAsciiVector(),
+ indices,
+ limit);
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToUC16Vector(),
+ indices,
+ limit);
+ }
+ }
+ }
+}
+
+
+template<typename ResultSeqString>
+MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
+ Isolate* isolate,
+ Handle<String> subject,
+ Handle<JSRegExp> pattern_regexp,
+ Handle<String> replacement) {
+ ASSERT(subject->IsFlat());
+ ASSERT(replacement->IsFlat());
+
+ ZoneScope zone_space(isolate, DELETE_ON_EXIT);
+ ZoneList<int> indices(8);
+ ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
+ String* pattern =
+ String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
+ int subject_len = subject->length();
+ int pattern_len = pattern->length();
+ int replacement_len = replacement->length();
+
+ FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
+
+ int matches = indices.length();
+ if (matches == 0) return *subject;
+
+ int result_len = (replacement_len - pattern_len) * matches + subject_len;
+ int subject_pos = 0;
+ int result_pos = 0;
+
+ Handle<ResultSeqString> result;
+ if (ResultSeqString::kHasAsciiEncoding) {
+ result = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawAsciiString(result_len));
+ } else {
+ result = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawTwoByteString(result_len));
+ }
+
+ for (int i = 0; i < matches; i++) {
+ // Copy non-matched subject content.
+ if (subject_pos < indices.at(i)) {
+ String::WriteToFlat(*subject,
+ result->GetChars() + result_pos,
+ subject_pos,
+ indices.at(i));
+ result_pos += indices.at(i) - subject_pos;
+ }
+
+ // Replace match.
+ if (replacement_len > 0) {
+ String::WriteToFlat(*replacement,
+ result->GetChars() + result_pos,
+ 0,
+ replacement_len);
+ result_pos += replacement_len;
+ }
+
+ subject_pos = indices.at(i) + pattern_len;
+ }
+ // Add remaining subject content at the end.
+ if (subject_pos < subject_len) {
+ String::WriteToFlat(*subject,
+ result->GetChars() + result_pos,
+ subject_pos,
+ subject_len);
+ }
+ return *result;
+}
+
MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
Isolate* isolate,
@@ -2800,6 +3017,20 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
bool is_global = regexp_handle->GetFlags().is_global();
+ // Shortcut for simple non-regexp global replacements
+ if (is_global &&
+ regexp->TypeTag() == JSRegExp::ATOM &&
+ compiled_replacement.simple_hint()) {
+ if (subject_handle->HasOnlyAsciiChars() &&
+ replacement_handle->HasOnlyAsciiChars()) {
+ return StringReplaceStringWithString<SeqAsciiString>(
+ isolate, subject_handle, regexp_handle, replacement_handle);
+ } else {
+ return StringReplaceStringWithString<SeqTwoByteString>(
+ isolate, subject_handle, regexp_handle, replacement_handle);
+ }
+ }
+
// Guessing the number of parts that the final result string is built
// from. Global regexps can match any number of times, so we guess
// conservatively.
@@ -2885,6 +3116,20 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
Handle<String> subject_handle(subject);
Handle<JSRegExp> regexp_handle(regexp);
+
+ // Shortcut for simple non-regexp global replacements
+ if (regexp_handle->GetFlags().is_global() &&
+ regexp_handle->TypeTag() == JSRegExp::ATOM) {
+ Handle<String> empty_string_handle(HEAP->empty_string());
+ if (subject_handle->HasOnlyAsciiChars()) {
+ return StringReplaceStringWithString<SeqAsciiString>(
+ isolate, subject_handle, regexp_handle, empty_string_handle);
+ } else {
+ return StringReplaceStringWithString<SeqTwoByteString>(
+ isolate, subject_handle, regexp_handle, empty_string_handle);
+ }
+ }
+
Handle<JSArray> last_match_info_handle(last_match_info);
Handle<Object> match = RegExpImpl::Exec(regexp_handle,
subject_handle,
@@ -4104,8 +4349,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
Handle<NumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, obj_value, details);
if (*extended_dictionary != *dictionary) {
- if (js_object->GetElementsKind() ==
- JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
+ if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
} else {
js_object->set_elements(*extended_dictionary);
@@ -4895,6 +5139,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol();
case JS_FUNCTION_TYPE:
+ case JS_FUNCTION_PROXY_TYPE:
return isolate->heap()->function_symbol();
default:
// For any kind of object not handled above, the spec rule for
@@ -5933,49 +6178,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
}
-void FindAsciiStringIndices(Vector<const char> subject,
- char pattern,
- ZoneList<int>* indices,
- unsigned int limit) {
- ASSERT(limit > 0);
- // Collect indices of pattern in subject using memchr.
- // Stop after finding at most limit values.
- const char* subject_start = reinterpret_cast<const char*>(subject.start());
- const char* subject_end = subject_start + subject.length();
- const char* pos = subject_start;
- while (limit > 0) {
- pos = reinterpret_cast<const char*>(
- memchr(pos, pattern, subject_end - pos));
- if (pos == NULL) return;
- indices->Add(static_cast<int>(pos - subject_start));
- pos++;
- limit--;
- }
-}
-
-
-template <typename SubjectChar, typename PatternChar>
-void FindStringIndices(Isolate* isolate,
- Vector<const SubjectChar> subject,
- Vector<const PatternChar> pattern,
- ZoneList<int>* indices,
- unsigned int limit) {
- ASSERT(limit > 0);
- // Collect indices of pattern in subject.
- // Stop after finding at most limit values.
- int pattern_length = pattern.length();
- int index = 0;
- StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
- while (limit > 0) {
- index = search.Search(subject, index);
- if (index < 0) return;
- indices->Add(index);
- index += pattern_length;
- limit--;
- }
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
ASSERT(args.length() == 3);
HandleScope handle_scope(isolate);
@@ -5987,6 +6189,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
int pattern_length = pattern->length();
RUNTIME_ASSERT(pattern_length > 0);
+ if (limit == 0xffffffffu) {
+ Handle<Object> cached_answer(StringSplitCache::Lookup(
+ isolate->heap()->string_split_cache(),
+ *subject,
+ *pattern));
+ if (*cached_answer != Smi::FromInt(0)) {
+ Handle<JSArray> result =
+ isolate->factory()->NewJSArrayWithElements(
+ Handle<FixedArray>::cast(cached_answer));
+ return *result;
+ }
+ }
+
// The limit can be very large (0xffffffffu), but since the pattern
// isn't empty, we can never create more parts than ~half the length
// of the subject.
@@ -6002,53 +6217,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
ZoneList<int> indices(initial_capacity);
if (!pattern->IsFlat()) FlattenString(pattern);
- // No allocation block.
- {
- AssertNoAllocation no_gc;
- String::FlatContent subject_content = subject->GetFlatContent();
- String::FlatContent pattern_content = pattern->GetFlatContent();
- ASSERT(subject_content.IsFlat());
- ASSERT(pattern_content.IsFlat());
- if (subject_content.IsAscii()) {
- Vector<const char> subject_vector = subject_content.ToAsciiVector();
- if (pattern_content.IsAscii()) {
- Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
- if (pattern_vector.length() == 1) {
- FindAsciiStringIndices(subject_vector,
- pattern_vector[0],
- &indices,
- limit);
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_vector,
- &indices,
- limit);
- }
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToUC16Vector(),
- &indices,
- limit);
- }
- } else {
- Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
- if (pattern->IsAsciiRepresentation()) {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToAsciiVector(),
- &indices,
- limit);
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToUC16Vector(),
- &indices,
- limit);
- }
- }
- }
+ FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
if (static_cast<uint32_t>(indices.length()) < limit) {
indices.Add(subject_length);
@@ -6080,6 +6249,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
part_start = part_end + pattern_length;
}
+ if (limit == 0xffffffffu) {
+ if (result->HasFastElements()) {
+ StringSplitCache::Enter(isolate->heap(),
+ isolate->heap()->string_split_cache(),
+ *subject,
+ *pattern,
+ *elements);
+ }
+ }
+
return *result;
}
@@ -6662,7 +6841,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
// Find total length of join result.
int string_length = 0;
bool is_ascii = separator->IsAsciiRepresentation();
- int max_string_length = SeqAsciiString::kMaxLength;
+ int max_string_length;
+ if (is_ascii) {
+ max_string_length = SeqAsciiString::kMaxLength;
+ } else {
+ max_string_length = SeqTwoByteString::kMaxLength;
+ }
bool overflow = false;
CONVERT_NUMBER_CHECKED(int, elements_length,
Int32, elements_array->length());
@@ -7640,7 +7824,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
Handle<Map> old_map(result->map());
Handle<Map> new_map =
isolate->factory()->CopyMapDropTransitions(old_map);
- new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
result->set_map(*new_map);
result->set_elements(*parameter_map);
@@ -7768,8 +7952,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
}
-static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
- int* total_argc) {
+static SmartArrayPointer<Object**> GetNonBoundArguments(int bound_argc,
+ int* total_argc) {
// Find frame containing arguments passed to the caller.
JavaScriptFrameIterator it;
JavaScriptFrame* frame = it.frame();
@@ -7785,7 +7969,7 @@ static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
&args_slots);
*total_argc = bound_argc + args_count;
- SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = args_slots[i].GetValue();
param_data[bound_argc + i] = val.location();
@@ -7797,7 +7981,7 @@ static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
int args_count = frame->ComputeParametersCount();
*total_argc = bound_argc + args_count;
- SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = Handle<Object>(frame->GetParameter(i));
param_data[bound_argc + i] = val.location();
@@ -7824,7 +8008,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
}
int total_argc = 0;
- SmartPointer<Object**> param_data =
+ SmartArrayPointer<Object**> param_data =
GetNonBoundArguments(bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
Handle<Object> val = Handle<Object>(bound_args->get(i));
@@ -7965,15 +8149,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
}
#endif
- // Compile the target function. Here we compile using CompileLazyInLoop in
- // order to get the optimized version. This helps code like delta-blue
- // that calls performance-critical routines through constructors. A
- // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
- // direct call. Since the in-loop tracking takes place through CallICs
- // this means that things called through constructors are never known to
- // be in loops. We compile them as if they are in loops here just in case.
+ // Compile the target function.
ASSERT(!function->is_compiled());
- if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
+ if (!CompileLazy(function, KEEP_EXCEPTION)) {
return Failure::Exception();
}
@@ -7987,6 +8165,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<JSFunction> function = args.at<JSFunction>(0);
+
+ // If the function is not compiled ignore the lazy
+ // recompilation. This can happen if the debugger is activated and
+ // the function is returned to the not compiled state.
+ if (!function->shared()->is_compiled()) {
+ function->ReplaceCode(function->shared()->code());
+ return function->code();
+ }
+
// If the function is not optimizable or debugger is active continue using the
// code from the full compiler.
if (!function->shared()->code()->optimizable() ||
@@ -8052,8 +8239,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
- } else {
- RUNTIME_ASSERT(!function->IsOptimized());
}
// Avoid doing too much work when running with --always-opt and keep
@@ -8072,8 +8257,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
it.Advance();
}
- // TODO(kasperl): For now, we cannot support removing the optimized
- // code when we have recursive invocations of the same function.
if (activations == 0) {
if (FLAG_trace_deopt) {
PrintF("[removing optimized code for: ");
@@ -8081,6 +8264,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
PrintF("]\n");
}
function->ReplaceCode(function->shared()->code());
+ } else {
+ Deoptimizer::DeoptimizeFunction(*function);
}
return isolate->heap()->undefined_value();
}
@@ -8261,6 +8446,55 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
+ RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 5);
+ CONVERT_CHECKED(JSReceiver, fun, args[0]);
+ Object* receiver = args[1];
+ CONVERT_CHECKED(JSObject, arguments, args[2]);
+ CONVERT_CHECKED(Smi, shift, args[3]);
+ CONVERT_CHECKED(Smi, arity, args[4]);
+
+ int offset = shift->value();
+ int argc = arity->value();
+ ASSERT(offset >= 0);
+ ASSERT(argc >= 0);
+
+ // If there are too many arguments, allocate argv via malloc.
+ const int argv_small_size = 10;
+ Handle<Object> argv_small_buffer[argv_small_size];
+ SmartArrayPointer<Handle<Object> > argv_large_buffer;
+ Handle<Object>* argv = argv_small_buffer;
+ if (argc > argv_small_size) {
+ argv = new Handle<Object>[argc];
+ if (argv == NULL) return isolate->StackOverflow();
+ argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ MaybeObject* maybe = arguments->GetElement(offset + i);
+ Object* object;
+ if (!maybe->To<Object>(&object)) return maybe;
+ argv[i] = Handle<Object>(object);
+ }
+
+ bool threw = false;
+ Handle<JSReceiver> hfun(fun);
+ Handle<Object> hreceiver(receiver);
+ Handle<Object> result = Execution::Call(
+ hfun, hreceiver, argc, reinterpret_cast<Object***>(argv), &threw, true);
+
+ if (threw) return Failure::Exception();
+ return *result;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -8737,7 +8971,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
static void PrintString(String* str) {
// not uncommon to have empty strings
if (str->length() > 0) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
PrintF("%s", *s);
}
@@ -9332,7 +9566,7 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
uint32_t length = static_cast<uint32_t>(array->length()->Number());
int element_count = 0;
switch (array->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
// Fast elements can't have lengths that are not representable by
// a 32-bit signed integer.
ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
@@ -9343,7 +9577,7 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dictionary(
NumberDictionary::cast(array->elements()));
int capacity = dictionary->Capacity();
@@ -9419,9 +9653,9 @@ static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
static void CollectElementIndices(Handle<JSObject> object,
uint32_t range,
List<uint32_t>* indices) {
- JSObject::ElementsKind kind = object->GetElementsKind();
+ ElementsKind kind = object->GetElementsKind();
switch (kind) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
if (range < length) length = range;
@@ -9432,7 +9666,7 @@ static void CollectElementIndices(Handle<JSObject> object,
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) {
@@ -9451,47 +9685,47 @@ static void CollectElementIndices(Handle<JSObject> object,
default: {
int dense_elements_length;
switch (kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
dense_elements_length =
ExternalPixelArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS: {
dense_elements_length =
ExternalByteArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
dense_elements_length =
ExternalUnsignedByteArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_SHORT_ELEMENTS: {
+ case EXTERNAL_SHORT_ELEMENTS: {
dense_elements_length =
ExternalShortArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
dense_elements_length =
ExternalUnsignedShortArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_INT_ELEMENTS: {
+ case EXTERNAL_INT_ELEMENTS: {
dense_elements_length =
ExternalIntArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
dense_elements_length =
ExternalUnsignedIntArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS: {
dense_elements_length =
ExternalFloatArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ case EXTERNAL_DOUBLE_ELEMENTS: {
dense_elements_length =
ExternalDoubleArray::cast(object->elements())->length();
break;
@@ -9540,7 +9774,7 @@ static bool IterateElements(Isolate* isolate,
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
@@ -9561,7 +9795,7 @@ static bool IterateElements(Isolate* isolate,
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(receiver->element_dictionary());
List<uint32_t> indices(dict->Capacity() / 2);
// Collect all indices in the object and the prototypes less
@@ -9583,7 +9817,7 @@ static bool IterateElements(Isolate* isolate,
}
break;
}
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
receiver->elements()));
for (uint32_t j = 0; j < length; j++) {
@@ -9592,42 +9826,42 @@ static bool IterateElements(Isolate* isolate,
}
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalByteArray, int8_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_SHORT_ELEMENTS: {
+ case EXTERNAL_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalShortArray, int16_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_INT_ELEMENTS: {
+ case EXTERNAL_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalIntArray, int32_t>(
isolate, receiver, true, false, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
isolate, receiver, true, false, visitor);
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS: {
IterateExternalArrayElements<ExternalFloatArray, float>(
isolate, receiver, false, false, visitor);
break;
}
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ case EXTERNAL_DOUBLE_ELEMENTS: {
IterateExternalArrayElements<ExternalDoubleArray, double>(
isolate, receiver, false, false, visitor);
break;
@@ -9999,7 +10233,7 @@ static MaybeObject* DebugLookupResultValue(Heap* heap,
}
case INTERCEPTOR:
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return heap->undefined_value();
@@ -10805,15 +11039,16 @@ class ScopeIterator {
at_local_(false) {
// Check whether the first scope is actually a local scope.
- if (context_->IsGlobalContext()) {
- // If there is a stack slot for .result then this local scope has been
- // created for evaluating top level code and it is not a real local scope.
- // Checking for the existence of .result seems fragile, but the scope info
- // saved with the code object does not otherwise have that information.
- int index = function_->shared()->scope_info()->
- StackSlotIndex(isolate_->heap()->result_symbol());
- at_local_ = index < 0;
- } else if (context_->IsFunctionContext()) {
+ // If there is a stack slot for .result then this local scope has been
+ // created for evaluating top level code and it is not a real local scope.
+ // Checking for the existence of .result seems fragile, but the scope info
+ // saved with the code object does not otherwise have that information.
+ int index = function_->shared()->scope_info()->
+ StackSlotIndex(isolate_->heap()->result_symbol());
+ if (index >= 0) {
+ local_done_ = true;
+ } else if (context_->IsGlobalContext() ||
+ context_->IsFunctionContext()) {
at_local_ = true;
} else if (context_->closure() != *function_) {
// The context_ is a block or with or catch block from the outer function.
@@ -10860,7 +11095,7 @@ class ScopeIterator {
}
// Return the type of the current scope.
- int Type() {
+ ScopeType Type() {
if (at_local_) {
return ScopeTypeLocal;
}
@@ -12289,7 +12524,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
// Sets a v8 flag.
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
CONVERT_CHECKED(String, arg, args[0]);
- SmartPointer<char> flags =
+ SmartArrayPointer<char> flags =
arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
FlagList::SetFlagsFromString(*flags, StrLength(*flags));
return isolate->heap()->undefined_value();
diff --git a/src/runtime.h b/src/runtime.h
index 91a19dfd..1538b7d8 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -79,6 +79,8 @@ namespace internal {
F(PreventExtensions, 1, 1)\
\
/* Utilities */ \
+ F(CheckIsBootstrapping, 0, 1) \
+ F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \
F(NewArgumentsFast, 3, 1) \
@@ -286,8 +288,12 @@ namespace internal {
\
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
+ F(CreateJSFunctionProxy, 4, 1) \
F(IsJSProxy, 1, 1) \
+ F(IsJSFunctionProxy, 1, 1) \
F(GetHandler, 1, 1) \
+ F(GetCallTrap, 1, 1) \
+ F(GetConstructTrap, 1, 1) \
F(Fix, 1, 1) \
\
/* Harmony weakmaps */ \
@@ -317,7 +323,7 @@ namespace internal {
F(StoreContextSlot, 4, 1) \
\
/* Declarations and initialization */ \
- F(DeclareGlobals, 4, 1) \
+ F(DeclareGlobals, 3, 1) \
F(DeclareContextSlot, 4, 1) \
F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
F(InitializeConstGlobal, 2, 1) \
@@ -663,6 +669,16 @@ class Runtime : public AllStatic {
static void PerformGC(Object* result);
};
+
+//---------------------------------------------------------------------------
+// Constants used by interface to runtime functions.
+
+enum kDeclareGlobalsFlags {
+ kDeclareGlobalsEvalFlag = 1 << 0,
+ kDeclareGlobalsStrictModeFlag = 1 << 1,
+ kDeclareGlobalsNativeFlag = 1 << 2
+};
+
} } // namespace v8::internal
#endif // V8_RUNTIME_H_
diff --git a/src/runtime.js b/src/runtime.js
index 4b600df7..14ff1b69 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -48,6 +48,7 @@ const $Number = global.Number;
const $Function = global.Function;
const $Boolean = global.Boolean;
const $NaN = 0/0;
+const builtins = this;
// ECMA-262 Section 11.9.3.
function EQUALS(y) {
@@ -365,7 +366,7 @@ function IN(x) {
// an expensive ToBoolean conversion in the generated code.
function INSTANCE_OF(F) {
var V = this;
- if (!IS_FUNCTION(F)) {
+ if (!IS_SPEC_FUNCTION(F)) {
throw %MakeTypeError('instanceof_function_expected', [V]);
}
@@ -407,7 +408,7 @@ function CALL_NON_FUNCTION() {
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof this]);
}
- return delegate.apply(this, arguments);
+ return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
}
@@ -416,7 +417,32 @@ function CALL_NON_FUNCTION_AS_CONSTRUCTOR() {
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof this]);
}
- return delegate.apply(this, arguments);
+ return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
+}
+
+
+function CALL_FUNCTION_PROXY() {
+ var arity = %_ArgumentsLength() - 1;
+ var proxy = %_Arguments(arity); // The proxy comes in as an additional arg.
+ var trap = %GetCallTrap(proxy);
+ return %Apply(trap, this, arguments, 0, arity);
+}
+
+
+function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR(proxy) {
+ var arity = %_ArgumentsLength() - 1;
+ var trap = %GetConstructTrap(proxy);
+ var receiver = void 0;
+ if (!IS_UNDEFINED(trap)) {
+ trap = %GetCallTrap(proxy);
+ var proto = proxy.prototype;
+ if (!IS_SPEC_OBJECT(proto) && proto !== null) {
+ throw MakeTypeError("proto_object_or_null", [proto]);
+ }
+ receiver = new global.Object();
+ receiver.__proto__ = proto;
+ }
+ return %Apply(trap, this, arguments, 1, arity);
}
@@ -427,7 +453,8 @@ function APPLY_PREPARE(args) {
// that takes care of more eventualities.
if (IS_ARRAY(args)) {
length = args.length;
- if (%_IsSmi(length) && length >= 0 && length < 0x800000 && IS_FUNCTION(this)) {
+ if (%_IsSmi(length) && length >= 0 && length < 0x800000 &&
+ IS_SPEC_FUNCTION(this)) {
return length;
}
}
@@ -441,7 +468,7 @@ function APPLY_PREPARE(args) {
throw %MakeRangeError('stack_overflow', []);
}
- if (!IS_FUNCTION(this)) {
+ if (!IS_SPEC_FUNCTION(this)) {
throw %MakeTypeError('apply_non_function', [ %ToString(this), typeof this ]);
}
@@ -609,13 +636,13 @@ function IsPrimitive(x) {
// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
var valueOf = x.valueOf;
- if (IS_FUNCTION(valueOf)) {
+ if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
var toString = x.toString;
- if (IS_FUNCTION(toString)) {
+ if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
@@ -627,13 +654,13 @@ function DefaultNumber(x) {
// ECMA-262, section 8.6.2.6, page 28.
function DefaultString(x) {
var toString = x.toString;
- if (IS_FUNCTION(toString)) {
+ if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
var valueOf = x.valueOf;
- if (IS_FUNCTION(valueOf)) {
+ if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc
index 28cf6e64..bcd0a1d6 100644
--- a/src/safepoint-table.cc
+++ b/src/safepoint-table.cc
@@ -68,8 +68,8 @@ SafepointTable::SafepointTable(Code* code) {
entries_ = pc_and_deoptimization_indexes_ +
(length_ * kPcAndDeoptimizationIndexSize);
ASSERT(entry_size_ > 0);
- ASSERT_EQ(SafepointEntry::DeoptimizationIndexField::max(),
- Safepoint::kNoDeoptimizationIndex);
+ STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
+ Safepoint::kNoDeoptimizationIndex);
}
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
deleted file mode 100644
index 62eee1a5..00000000
--- a/src/scanner-base.cc
+++ /dev/null
@@ -1,1090 +0,0 @@
-// Copyright 2011 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.
-
-// Features shared by parsing and pre-parsing scanners.
-
-#include "../include/v8stdint.h"
-#include "scanner-base.h"
-#include "char-predicates-inl.h"
-
-namespace v8 {
-namespace internal {
-
-// ----------------------------------------------------------------------------
-// Scanner
-
-Scanner::Scanner(UnicodeCache* unicode_cache)
- : unicode_cache_(unicode_cache) { }
-
-
-uc32 Scanner::ScanHexNumber(int expected_length) {
- ASSERT(expected_length <= 4); // prevent overflow
-
- uc32 digits[4] = { 0, 0, 0, 0 };
- uc32 x = 0;
- for (int i = 0; i < expected_length; i++) {
- digits[i] = c0_;
- int d = HexValue(c0_);
- if (d < 0) {
- // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
- // should be illegal, but other JS VMs just return the
- // non-escaped version of the original character.
-
- // Push back digits that we have advanced past.
- for (int j = i-1; j >= 0; j--) {
- PushBack(digits[j]);
- }
- return -1;
- }
- x = x * 16 + d;
- Advance();
- }
-
- return x;
-}
-
-
-
-// ----------------------------------------------------------------------------
-// JavaScriptScanner
-
-JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
- : Scanner(scanner_contants),
- octal_pos_(Location::invalid()),
- harmony_block_scoping_(false) { }
-
-
-void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
- source_ = source;
- // Need to capture identifiers in order to recognize "get" and "set"
- // in object literals.
- Init();
- // Skip initial whitespace allowing HTML comment ends just like
- // after a newline and scan first token.
- has_line_terminator_before_next_ = true;
- SkipWhiteSpace();
- Scan();
-}
-
-
-// Ensure that tokens can be stored in a byte.
-STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
-
-// Table of one-character tokens, by character (0x00..0x7f only).
-static const byte one_char_tokens[] = {
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LPAREN, // 0x28
- Token::RPAREN, // 0x29
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COMMA, // 0x2c
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COLON, // 0x3a
- Token::SEMICOLON, // 0x3b
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::CONDITIONAL, // 0x3f
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACK, // 0x5b
- Token::ILLEGAL,
- Token::RBRACK, // 0x5d
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACE, // 0x7b
- Token::ILLEGAL,
- Token::RBRACE, // 0x7d
- Token::BIT_NOT, // 0x7e
- Token::ILLEGAL
-};
-
-
-Token::Value JavaScriptScanner::Next() {
- current_ = next_;
- has_line_terminator_before_next_ = false;
- has_multiline_comment_before_next_ = false;
- if (static_cast<unsigned>(c0_) <= 0x7f) {
- Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
- if (token != Token::ILLEGAL) {
- int pos = source_pos();
- next_.token = token;
- next_.location.beg_pos = pos;
- next_.location.end_pos = pos + 1;
- Advance();
- return current_.token;
- }
- }
- Scan();
- return current_.token;
-}
-
-
-static inline bool IsByteOrderMark(uc32 c) {
- // The Unicode value U+FFFE is guaranteed never to be assigned as a
- // Unicode character; this implies that in a Unicode context the
- // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
- // character expressed in little-endian byte order (since it could
- // not be a U+FFFE character expressed in big-endian byte
- // order). Nevertheless, we check for it to be compatible with
- // Spidermonkey.
- return c == 0xFEFF || c == 0xFFFE;
-}
-
-
-bool JavaScriptScanner::SkipWhiteSpace() {
- int start_position = source_pos();
-
- while (true) {
- // We treat byte-order marks (BOMs) as whitespace for better
- // compatibility with Spidermonkey and other JavaScript engines.
- while (unicode_cache_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) {
- // IsWhiteSpace() includes line terminators!
- if (unicode_cache_->IsLineTerminator(c0_)) {
- // Ignore line terminators, but remember them. This is necessary
- // for automatic semicolon insertion.
- has_line_terminator_before_next_ = true;
- }
- Advance();
- }
-
- // If there is an HTML comment end '-->' at the beginning of a
- // line (with only whitespace in front of it), we treat the rest
- // of the line as a comment. This is in line with the way
- // SpiderMonkey handles it.
- if (c0_ == '-' && has_line_terminator_before_next_) {
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>') {
- // Treat the rest of the line as a comment.
- SkipSingleLineComment();
- // Continue skipping white space after the comment.
- continue;
- }
- PushBack('-'); // undo Advance()
- }
- PushBack('-'); // undo Advance()
- }
- // Return whether or not we skipped any characters.
- return source_pos() != start_position;
- }
-}
-
-
-Token::Value JavaScriptScanner::SkipSingleLineComment() {
- Advance();
-
- // The line terminator at the end of the line is not considered
- // to be part of the single-line comment; it is recognized
- // separately by the lexical grammar and becomes part of the
- // stream of input elements for the syntactic grammar (see
- // ECMA-262, section 7.4).
- while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
- Advance();
- }
-
- return Token::WHITESPACE;
-}
-
-
-Token::Value JavaScriptScanner::SkipMultiLineComment() {
- ASSERT(c0_ == '*');
- Advance();
-
- while (c0_ >= 0) {
- uc32 ch = c0_;
- Advance();
- if (unicode_cache_->IsLineTerminator(ch)) {
- // Following ECMA-262, section 7.4, a comment containing
- // a newline will make the comment count as a line-terminator.
- has_multiline_comment_before_next_ = true;
- }
- // If we have reached the end of the multi-line comment, we
- // consume the '/' and insert a whitespace. This way all
- // multi-line comments are treated as whitespace.
- if (ch == '*' && c0_ == '/') {
- c0_ = ' ';
- return Token::WHITESPACE;
- }
- }
-
- // Unterminated multi-line comment.
- return Token::ILLEGAL;
-}
-
-
-Token::Value JavaScriptScanner::ScanHtmlComment() {
- // Check for <!-- comments.
- ASSERT(c0_ == '!');
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '-') return SkipSingleLineComment();
- PushBack('-'); // undo Advance()
- }
- PushBack('!'); // undo Advance()
- ASSERT(c0_ == '!');
- return Token::LT;
-}
-
-
-void JavaScriptScanner::Scan() {
- next_.literal_chars = NULL;
- Token::Value token;
- do {
- // Remember the position of the next token
- next_.location.beg_pos = source_pos();
-
- switch (c0_) {
- case ' ':
- case '\t':
- Advance();
- token = Token::WHITESPACE;
- break;
-
- case '\n':
- Advance();
- has_line_terminator_before_next_ = true;
- token = Token::WHITESPACE;
- break;
-
- case '"': case '\'':
- token = ScanString();
- break;
-
- case '<':
- // < <= << <<= <!--
- Advance();
- if (c0_ == '=') {
- token = Select(Token::LTE);
- } else if (c0_ == '<') {
- token = Select('=', Token::ASSIGN_SHL, Token::SHL);
- } else if (c0_ == '!') {
- token = ScanHtmlComment();
- } else {
- token = Token::LT;
- }
- break;
-
- case '>':
- // > >= >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::GTE);
- } else if (c0_ == '>') {
- // >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::ASSIGN_SAR);
- } else if (c0_ == '>') {
- token = Select('=', Token::ASSIGN_SHR, Token::SHR);
- } else {
- token = Token::SAR;
- }
- } else {
- token = Token::GT;
- }
- break;
-
- case '=':
- // = == ===
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::EQ_STRICT, Token::EQ);
- } else {
- token = Token::ASSIGN;
- }
- break;
-
- case '!':
- // ! != !==
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::NE_STRICT, Token::NE);
- } else {
- token = Token::NOT;
- }
- break;
-
- case '+':
- // + ++ +=
- Advance();
- if (c0_ == '+') {
- token = Select(Token::INC);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_ADD);
- } else {
- token = Token::ADD;
- }
- break;
-
- case '-':
- // - -- --> -=
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>' && has_line_terminator_before_next_) {
- // For compatibility with SpiderMonkey, we skip lines that
- // start with an HTML comment end '-->'.
- token = SkipSingleLineComment();
- } else {
- token = Token::DEC;
- }
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_SUB);
- } else {
- token = Token::SUB;
- }
- break;
-
- case '*':
- // * *=
- token = Select('=', Token::ASSIGN_MUL, Token::MUL);
- break;
-
- case '%':
- // % %=
- token = Select('=', Token::ASSIGN_MOD, Token::MOD);
- break;
-
- case '/':
- // / // /* /=
- Advance();
- if (c0_ == '/') {
- token = SkipSingleLineComment();
- } else if (c0_ == '*') {
- token = SkipMultiLineComment();
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_DIV);
- } else {
- token = Token::DIV;
- }
- break;
-
- case '&':
- // & && &=
- Advance();
- if (c0_ == '&') {
- token = Select(Token::AND);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_AND);
- } else {
- token = Token::BIT_AND;
- }
- break;
-
- case '|':
- // | || |=
- Advance();
- if (c0_ == '|') {
- token = Select(Token::OR);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_OR);
- } else {
- token = Token::BIT_OR;
- }
- break;
-
- case '^':
- // ^ ^=
- token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
- break;
-
- case '.':
- // . Number
- Advance();
- if (IsDecimalDigit(c0_)) {
- token = ScanNumber(true);
- } else {
- token = Token::PERIOD;
- }
- break;
-
- case ':':
- token = Select(Token::COLON);
- break;
-
- case ';':
- token = Select(Token::SEMICOLON);
- break;
-
- case ',':
- token = Select(Token::COMMA);
- break;
-
- case '(':
- token = Select(Token::LPAREN);
- break;
-
- case ')':
- token = Select(Token::RPAREN);
- break;
-
- case '[':
- token = Select(Token::LBRACK);
- break;
-
- case ']':
- token = Select(Token::RBRACK);
- break;
-
- case '{':
- token = Select(Token::LBRACE);
- break;
-
- case '}':
- token = Select(Token::RBRACE);
- break;
-
- case '?':
- token = Select(Token::CONDITIONAL);
- break;
-
- case '~':
- token = Select(Token::BIT_NOT);
- break;
-
- default:
- if (unicode_cache_->IsIdentifierStart(c0_)) {
- token = ScanIdentifierOrKeyword();
- } else if (IsDecimalDigit(c0_)) {
- token = ScanNumber(false);
- } else if (SkipWhiteSpace()) {
- token = Token::WHITESPACE;
- } else if (c0_ < 0) {
- token = Token::EOS;
- } else {
- token = Select(Token::ILLEGAL);
- }
- break;
- }
-
- // Continue scanning for tokens as long as we're just skipping
- // whitespace.
- } while (token == Token::WHITESPACE);
-
- next_.location.end_pos = source_pos();
- next_.token = token;
-}
-
-
-void JavaScriptScanner::SeekForward(int pos) {
- // After this call, we will have the token at the given position as
- // the "next" token. The "current" token will be invalid.
- if (pos == next_.location.beg_pos) return;
- int current_pos = source_pos();
- ASSERT_EQ(next_.location.end_pos, current_pos);
- // Positions inside the lookahead token aren't supported.
- ASSERT(pos >= current_pos);
- if (pos != current_pos) {
- source_->SeekForward(pos - source_->pos());
- Advance();
- // This function is only called to seek to the location
- // of the end of a function (at the "}" token). It doesn't matter
- // whether there was a line terminator in the part we skip.
- has_line_terminator_before_next_ = false;
- has_multiline_comment_before_next_ = false;
- }
- Scan();
-}
-
-
-void JavaScriptScanner::ScanEscape() {
- uc32 c = c0_;
- Advance();
-
- // Skip escaped newlines.
- if (unicode_cache_->IsLineTerminator(c)) {
- // Allow CR+LF newlines in multiline string literals.
- if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
- // Allow LF+CR newlines in multiline string literals.
- if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
- return;
- }
-
- switch (c) {
- case '\'': // fall through
- case '"' : // fall through
- case '\\': break;
- case 'b' : c = '\b'; break;
- case 'f' : c = '\f'; break;
- case 'n' : c = '\n'; break;
- case 'r' : c = '\r'; break;
- case 't' : c = '\t'; break;
- case 'u' : {
- c = ScanHexNumber(4);
- if (c < 0) c = 'u';
- break;
- }
- case 'v' : c = '\v'; break;
- case 'x' : {
- c = ScanHexNumber(2);
- if (c < 0) c = 'x';
- break;
- }
- case '0' : // fall through
- case '1' : // fall through
- case '2' : // fall through
- case '3' : // fall through
- case '4' : // fall through
- case '5' : // fall through
- case '6' : // fall through
- case '7' : c = ScanOctalEscape(c, 2); break;
- }
-
- // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
- // should be illegal, but they are commonly handled
- // as non-escaped characters by JS VMs.
- AddLiteralChar(c);
-}
-
-
-// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
-// ECMA-262. Other JS VMs support them.
-uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
- uc32 x = c - '0';
- int i = 0;
- for (; i < length; i++) {
- int d = c0_ - '0';
- if (d < 0 || d > 7) break;
- int nx = x * 8 + d;
- if (nx >= 256) break;
- x = nx;
- Advance();
- }
- // Anything except '\0' is an octal escape sequence, illegal in strict mode.
- // Remember the position of octal escape sequences so that an error
- // can be reported later (in strict mode).
- // We don't report the error immediately, because the octal escape can
- // occur before the "use strict" directive.
- if (c != '0' || i > 0) {
- octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
- }
- return x;
-}
-
-
-Token::Value JavaScriptScanner::ScanString() {
- uc32 quote = c0_;
- Advance(); // consume quote
-
- LiteralScope literal(this);
- while (c0_ != quote && c0_ >= 0
- && !unicode_cache_->IsLineTerminator(c0_)) {
- uc32 c = c0_;
- Advance();
- if (c == '\\') {
- if (c0_ < 0) return Token::ILLEGAL;
- ScanEscape();
- } else {
- AddLiteralChar(c);
- }
- }
- if (c0_ != quote) return Token::ILLEGAL;
- literal.Complete();
-
- Advance(); // consume quote
- return Token::STRING;
-}
-
-
-void JavaScriptScanner::ScanDecimalDigits() {
- while (IsDecimalDigit(c0_))
- AddLiteralCharAdvance();
-}
-
-
-Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
- ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
-
- enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
-
- LiteralScope literal(this);
- if (seen_period) {
- // we have already seen a decimal point of the float
- AddLiteralChar('.');
- ScanDecimalDigits(); // we know we have at least one digit
-
- } else {
- // if the first character is '0' we must check for octals and hex
- if (c0_ == '0') {
- int start_pos = source_pos(); // For reporting octal positions.
- AddLiteralCharAdvance();
-
- // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
- if (c0_ == 'x' || c0_ == 'X') {
- // hex number
- kind = HEX;
- AddLiteralCharAdvance();
- if (!IsHexDigit(c0_)) {
- // we must have at least one hex digit after 'x'/'X'
- return Token::ILLEGAL;
- }
- while (IsHexDigit(c0_)) {
- AddLiteralCharAdvance();
- }
- } else if ('0' <= c0_ && c0_ <= '7') {
- // (possible) octal number
- kind = OCTAL;
- while (true) {
- if (c0_ == '8' || c0_ == '9') {
- kind = DECIMAL;
- break;
- }
- if (c0_ < '0' || '7' < c0_) {
- // Octal literal finished.
- octal_pos_ = Location(start_pos, source_pos());
- break;
- }
- AddLiteralCharAdvance();
- }
- }
- }
-
- // Parse decimal digits and allow trailing fractional part.
- if (kind == DECIMAL) {
- ScanDecimalDigits(); // optional
- if (c0_ == '.') {
- AddLiteralCharAdvance();
- ScanDecimalDigits(); // optional
- }
- }
- }
-
- // scan exponent, if any
- if (c0_ == 'e' || c0_ == 'E') {
- ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
- if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
- // scan exponent
- AddLiteralCharAdvance();
- if (c0_ == '+' || c0_ == '-')
- AddLiteralCharAdvance();
- if (!IsDecimalDigit(c0_)) {
- // we must have at least one decimal digit after 'e'/'E'
- return Token::ILLEGAL;
- }
- ScanDecimalDigits();
- }
-
- // The source character immediately following a numeric literal must
- // not be an identifier start or a decimal digit; see ECMA-262
- // section 7.8.3, page 17 (note that we read only one decimal digit
- // if the value is 0).
- if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
- return Token::ILLEGAL;
-
- literal.Complete();
-
- return Token::NUMBER;
-}
-
-
-uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
- Advance();
- if (c0_ != 'u') return -1;
- Advance();
- uc32 result = ScanHexNumber(4);
- if (result < 0) PushBack('u');
- return result;
-}
-
-
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
- KEYWORD_GROUP('b') \
- KEYWORD("break", Token::BREAK) \
- KEYWORD_GROUP('c') \
- KEYWORD("case", Token::CASE) \
- KEYWORD("catch", Token::CATCH) \
- KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("const", Token::CONST) \
- KEYWORD("continue", Token::CONTINUE) \
- KEYWORD_GROUP('d') \
- KEYWORD("debugger", Token::DEBUGGER) \
- KEYWORD("default", Token::DEFAULT) \
- KEYWORD("delete", Token::DELETE) \
- KEYWORD("do", Token::DO) \
- KEYWORD_GROUP('e') \
- KEYWORD("else", Token::ELSE) \
- KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
- KEYWORD_GROUP('f') \
- KEYWORD("false", Token::FALSE_LITERAL) \
- KEYWORD("finally", Token::FINALLY) \
- KEYWORD("for", Token::FOR) \
- KEYWORD("function", Token::FUNCTION) \
- KEYWORD_GROUP('i') \
- KEYWORD("if", Token::IF) \
- KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("in", Token::IN) \
- KEYWORD("instanceof", Token::INSTANCEOF) \
- KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('l') \
- KEYWORD("let", harmony_block_scoping \
- ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('n') \
- KEYWORD("new", Token::NEW) \
- KEYWORD("null", Token::NULL_LITERAL) \
- KEYWORD_GROUP('p') \
- KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('r') \
- KEYWORD("return", Token::RETURN) \
- KEYWORD_GROUP('s') \
- KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("switch", Token::SWITCH) \
- KEYWORD_GROUP('t') \
- KEYWORD("this", Token::THIS) \
- KEYWORD("throw", Token::THROW) \
- KEYWORD("true", Token::TRUE_LITERAL) \
- KEYWORD("try", Token::TRY) \
- KEYWORD("typeof", Token::TYPEOF) \
- KEYWORD_GROUP('v') \
- KEYWORD("var", Token::VAR) \
- KEYWORD("void", Token::VOID) \
- KEYWORD_GROUP('w') \
- KEYWORD("while", Token::WHILE) \
- KEYWORD("with", Token::WITH) \
- KEYWORD_GROUP('y') \
- KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
-
-
-static Token::Value KeywordOrIdentifierToken(const char* input,
- int input_length,
- bool harmony_block_scoping) {
- ASSERT(input_length >= 1);
- const int kMinLength = 2;
- const int kMaxLength = 10;
- if (input_length < kMinLength || input_length > kMaxLength) {
- return Token::IDENTIFIER;
- }
- switch (input[0]) {
- default:
-#define KEYWORD_GROUP_CASE(ch) \
- break; \
- case ch:
-#define KEYWORD(keyword, token) \
- { \
- /* 'keyword' is a char array, so sizeof(keyword) is */ \
- /* strlen(keyword) plus 1 for the NUL char. */ \
- const int keyword_length = sizeof(keyword) - 1; \
- STATIC_ASSERT(keyword_length >= kMinLength); \
- STATIC_ASSERT(keyword_length <= kMaxLength); \
- if (input_length == keyword_length && \
- input[1] == keyword[1] && \
- (keyword_length <= 2 || input[2] == keyword[2]) && \
- (keyword_length <= 3 || input[3] == keyword[3]) && \
- (keyword_length <= 4 || input[4] == keyword[4]) && \
- (keyword_length <= 5 || input[5] == keyword[5]) && \
- (keyword_length <= 6 || input[6] == keyword[6]) && \
- (keyword_length <= 7 || input[7] == keyword[7]) && \
- (keyword_length <= 8 || input[8] == keyword[8]) && \
- (keyword_length <= 9 || input[9] == keyword[9])) { \
- return token; \
- } \
- }
- KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
- }
- return Token::IDENTIFIER;
-}
-
-
-Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
- ASSERT(unicode_cache_->IsIdentifierStart(c0_));
- LiteralScope literal(this);
- // Scan identifier start character.
- if (c0_ == '\\') {
- uc32 c = ScanIdentifierUnicodeEscape();
- // Only allow legal identifier start characters.
- if (c < 0 ||
- c == '\\' || // No recursive escapes.
- !unicode_cache_->IsIdentifierStart(c)) {
- return Token::ILLEGAL;
- }
- AddLiteralChar(c);
- return ScanIdentifierSuffix(&literal);
- }
-
- uc32 first_char = c0_;
- Advance();
- AddLiteralChar(first_char);
-
- // Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ != '\\') {
- uc32 next_char = c0_;
- Advance();
- AddLiteralChar(next_char);
- continue;
- }
- // Fallthrough if no longer able to complete keyword.
- return ScanIdentifierSuffix(&literal);
- }
-
- literal.Complete();
-
- if (next_.literal_chars->is_ascii()) {
- Vector<const char> chars = next_.literal_chars->ascii_literal();
- return KeywordOrIdentifierToken(chars.start(),
- chars.length(),
- harmony_block_scoping_);
- }
-
- return Token::IDENTIFIER;
-}
-
-
-Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
- // Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ == '\\') {
- uc32 c = ScanIdentifierUnicodeEscape();
- // Only allow legal identifier part characters.
- if (c < 0 ||
- c == '\\' ||
- !unicode_cache_->IsIdentifierPart(c)) {
- return Token::ILLEGAL;
- }
- AddLiteralChar(c);
- } else {
- AddLiteralChar(c0_);
- Advance();
- }
- }
- literal->Complete();
-
- return Token::IDENTIFIER;
-}
-
-
-bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
- // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
- bool in_character_class = false;
-
- // Previous token is either '/' or '/=', in the second case, the
- // pattern starts at =.
- next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
- next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
-
- // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
- // the scanner should pass uninterpreted bodies to the RegExp
- // constructor.
- LiteralScope literal(this);
- if (seen_equal) {
- AddLiteralChar('=');
- }
-
- while (c0_ != '/' || in_character_class) {
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
- if (c0_ == '\\') { // Escape sequence.
- AddLiteralCharAdvance();
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
- AddLiteralCharAdvance();
- // If the escape allows more characters, i.e., \x??, \u????, or \c?,
- // only "safe" characters are allowed (letters, digits, underscore),
- // otherwise the escape isn't valid and the invalid character has
- // its normal meaning. I.e., we can just continue scanning without
- // worrying whether the following characters are part of the escape
- // or not, since any '/', '\\' or '[' is guaranteed to not be part
- // of the escape sequence.
-
- // TODO(896): At some point, parse RegExps more throughly to capture
- // octal esacpes in strict mode.
- } else { // Unescaped character.
- if (c0_ == '[') in_character_class = true;
- if (c0_ == ']') in_character_class = false;
- AddLiteralCharAdvance();
- }
- }
- Advance(); // consume '/'
-
- literal.Complete();
-
- return true;
-}
-
-
-bool JavaScriptScanner::ScanLiteralUnicodeEscape() {
- ASSERT(c0_ == '\\');
- uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0};
- Advance();
- int i = 1;
- if (c0_ == 'u') {
- i++;
- while (i < 6) {
- Advance();
- if (!IsHexDigit(c0_)) break;
- chars_read[i] = c0_;
- i++;
- }
- }
- if (i < 6) {
- // Incomplete escape. Undo all advances and return false.
- while (i > 0) {
- i--;
- PushBack(chars_read[i]);
- }
- return false;
- }
- // Complete escape. Add all chars to current literal buffer.
- for (int i = 0; i < 6; i++) {
- AddLiteralChar(chars_read[i]);
- }
- return true;
-}
-
-
-bool JavaScriptScanner::ScanRegExpFlags() {
- // Scan regular expression flags.
- LiteralScope literal(this);
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ != '\\') {
- AddLiteralCharAdvance();
- } else {
- if (!ScanLiteralUnicodeEscape()) {
- break;
- }
- }
- }
- literal.Complete();
-
- next_.location.end_pos = source_pos() - 1;
- return true;
-}
-
-} } // namespace v8::internal
diff --git a/src/scanner-base.h b/src/scanner-base.h
deleted file mode 100644
index d68d240e..00000000
--- a/src/scanner-base.h
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2011 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.
-
-// Features shared by parsing and pre-parsing scanners.
-
-#ifndef V8_SCANNER_BASE_H_
-#define V8_SCANNER_BASE_H_
-
-#include "allocation.h"
-#include "char-predicates.h"
-#include "checks.h"
-#include "globals.h"
-#include "token.h"
-#include "unicode-inl.h"
-#include "utils.h"
-
-namespace v8 {
-namespace internal {
-
-// Returns the value (0 .. 15) of a hexadecimal character c.
-// If c is not a legal hexadecimal character, returns a value < 0.
-inline int HexValue(uc32 c) {
- c -= '0';
- if (static_cast<unsigned>(c) <= 9) return c;
- c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
- if (static_cast<unsigned>(c) <= 5) return c + 10;
- return -1;
-}
-
-
-// ---------------------------------------------------------------------
-// Buffered stream of characters, using an internal UC16 buffer.
-
-class UC16CharacterStream {
- public:
- UC16CharacterStream() : pos_(0) { }
- virtual ~UC16CharacterStream() { }
-
- // Returns and advances past the next UC16 character in the input
- // stream. If there are no more characters, it returns a negative
- // value.
- inline uc32 Advance() {
- if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
- pos_++;
- return static_cast<uc32>(*(buffer_cursor_++));
- }
- // Note: currently the following increment is necessary to avoid a
- // parser problem! The scanner treats the final kEndOfInput as
- // a character with a position, and does math relative to that
- // position.
- pos_++;
-
- return kEndOfInput;
- }
-
- // Return the current position in the character stream.
- // Starts at zero.
- inline unsigned pos() const { return pos_; }
-
- // Skips forward past the next character_count UC16 characters
- // in the input, or until the end of input if that comes sooner.
- // Returns the number of characters actually skipped. If less
- // than character_count,
- inline unsigned SeekForward(unsigned character_count) {
- unsigned buffered_chars =
- static_cast<unsigned>(buffer_end_ - buffer_cursor_);
- if (character_count <= buffered_chars) {
- buffer_cursor_ += character_count;
- pos_ += character_count;
- return character_count;
- }
- return SlowSeekForward(character_count);
- }
-
- // Pushes back the most recently read UC16 character (or negative
- // value if at end of input), i.e., the value returned by the most recent
- // call to Advance.
- // Must not be used right after calling SeekForward.
- virtual void PushBack(int32_t character) = 0;
-
- protected:
- static const uc32 kEndOfInput = -1;
-
- // Ensures that the buffer_cursor_ points to the character at
- // position pos_ of the input, if possible. If the position
- // is at or after the end of the input, return false. If there
- // are more characters available, return true.
- virtual bool ReadBlock() = 0;
- virtual unsigned SlowSeekForward(unsigned character_count) = 0;
-
- const uc16* buffer_cursor_;
- const uc16* buffer_end_;
- unsigned pos_;
-};
-
-
-class UnicodeCache {
-// ---------------------------------------------------------------------
-// Caching predicates used by scanners.
- public:
- UnicodeCache() {}
- typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
-
- StaticResource<Utf8Decoder>* utf8_decoder() {
- return &utf8_decoder_;
- }
-
- bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
- bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
- bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
- bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
-
- private:
-
- unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
- unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
- unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
- unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
- StaticResource<Utf8Decoder> utf8_decoder_;
-
- DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
-};
-
-
-// ----------------------------------------------------------------------------
-// LiteralBuffer - Collector of chars of literals.
-
-class LiteralBuffer {
- public:
- LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
-
- ~LiteralBuffer() {
- if (backing_store_.length() > 0) {
- backing_store_.Dispose();
- }
- }
-
- inline void AddChar(uc16 character) {
- if (position_ >= backing_store_.length()) ExpandBuffer();
- if (is_ascii_) {
- if (character < kMaxAsciiCharCodeU) {
- backing_store_[position_] = static_cast<byte>(character);
- position_ += kASCIISize;
- return;
- }
- ConvertToUC16();
- }
- *reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
- position_ += kUC16Size;
- }
-
- bool is_ascii() { return is_ascii_; }
-
- Vector<const uc16> uc16_literal() {
- ASSERT(!is_ascii_);
- ASSERT((position_ & 0x1) == 0);
- return Vector<const uc16>(
- reinterpret_cast<const uc16*>(backing_store_.start()),
- position_ >> 1);
- }
-
- Vector<const char> ascii_literal() {
- ASSERT(is_ascii_);
- return Vector<const char>(
- reinterpret_cast<const char*>(backing_store_.start()),
- position_);
- }
-
- int length() {
- return is_ascii_ ? position_ : (position_ >> 1);
- }
-
- void Reset() {
- position_ = 0;
- is_ascii_ = true;
- }
- private:
- static const int kInitialCapacity = 16;
- static const int kGrowthFactory = 4;
- static const int kMinConversionSlack = 256;
- static const int kMaxGrowth = 1 * MB;
- inline int NewCapacity(int min_capacity) {
- int capacity = Max(min_capacity, backing_store_.length());
- int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
- return new_capacity;
- }
-
- void ExpandBuffer() {
- Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
- memcpy(new_store.start(), backing_store_.start(), position_);
- backing_store_.Dispose();
- backing_store_ = new_store;
- }
-
- void ConvertToUC16() {
- ASSERT(is_ascii_);
- Vector<byte> new_store;
- int new_content_size = position_ * kUC16Size;
- if (new_content_size >= backing_store_.length()) {
- // Ensure room for all currently read characters as UC16 as well
- // as the character about to be stored.
- new_store = Vector<byte>::New(NewCapacity(new_content_size));
- } else {
- new_store = backing_store_;
- }
- char* src = reinterpret_cast<char*>(backing_store_.start());
- uc16* dst = reinterpret_cast<uc16*>(new_store.start());
- for (int i = position_ - 1; i >= 0; i--) {
- dst[i] = src[i];
- }
- if (new_store.start() != backing_store_.start()) {
- backing_store_.Dispose();
- backing_store_ = new_store;
- }
- position_ = new_content_size;
- is_ascii_ = false;
- }
-
- bool is_ascii_;
- int position_;
- Vector<byte> backing_store_;
-
- DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
-};
-
-
-// ----------------------------------------------------------------------------
-// Scanner base-class.
-
-// Generic functionality used by both JSON and JavaScript scanners.
-class Scanner {
- public:
- // -1 is outside of the range of any real source code.
- static const int kNoOctalLocation = -1;
-
- typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
-
- class LiteralScope {
- public:
- explicit LiteralScope(Scanner* self);
- ~LiteralScope();
- void Complete();
-
- private:
- Scanner* scanner_;
- bool complete_;
- };
-
- explicit Scanner(UnicodeCache* scanner_contants);
-
- // Returns the current token again.
- Token::Value current_token() { return current_.token; }
-
- // One token look-ahead (past the token returned by Next()).
- Token::Value peek() const { return next_.token; }
-
- struct Location {
- Location(int b, int e) : beg_pos(b), end_pos(e) { }
- Location() : beg_pos(0), end_pos(0) { }
-
- bool IsValid() const {
- return beg_pos >= 0 && end_pos >= beg_pos;
- }
-
- static Location invalid() { return Location(-1, -1); }
-
- int beg_pos;
- int end_pos;
- };
-
- // Returns the location information for the current token
- // (the token returned by Next()).
- Location location() const { return current_.location; }
- Location peek_location() const { return next_.location; }
-
- // Returns the literal string, if any, for the current token (the
- // token returned by Next()). The string is 0-terminated and in
- // UTF-8 format; they may contain 0-characters. Literal strings are
- // collected for identifiers, strings, and numbers.
- // These functions only give the correct result if the literal
- // was scanned between calls to StartLiteral() and TerminateLiteral().
- bool is_literal_ascii() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->is_ascii();
- }
- Vector<const char> literal_ascii_string() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->ascii_literal();
- }
- Vector<const uc16> literal_uc16_string() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->uc16_literal();
- }
- int literal_length() const {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->length();
- }
-
- bool literal_contains_escapes() const {
- Location location = current_.location;
- int source_length = (location.end_pos - location.beg_pos);
- if (current_.token == Token::STRING) {
- // Subtract delimiters.
- source_length -= 2;
- }
- return current_.literal_chars->length() != source_length;
- }
-
- // Returns the literal string for the next token (the token that
- // would be returned if Next() were called).
- bool is_next_literal_ascii() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->is_ascii();
- }
- Vector<const char> next_literal_ascii_string() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->ascii_literal();
- }
- Vector<const uc16> next_literal_uc16_string() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->uc16_literal();
- }
- int next_literal_length() const {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->length();
- }
-
- static const int kCharacterLookaheadBufferSize = 1;
-
- protected:
- // The current and look-ahead token.
- struct TokenDesc {
- Token::Value token;
- Location location;
- LiteralBuffer* literal_chars;
- };
-
- // Call this after setting source_ to the input.
- void Init() {
- // Set c0_ (one character ahead)
- STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
- Advance();
- // Initialize current_ to not refer to a literal.
- current_.literal_chars = NULL;
- }
-
- // Literal buffer support
- inline void StartLiteral() {
- LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
- &literal_buffer2_ : &literal_buffer1_;
- free_buffer->Reset();
- next_.literal_chars = free_buffer;
- }
-
- inline void AddLiteralChar(uc32 c) {
- ASSERT_NOT_NULL(next_.literal_chars);
- next_.literal_chars->AddChar(c);
- }
-
- // Complete scanning of a literal.
- inline void TerminateLiteral() {
- // Does nothing in the current implementation.
- }
-
- // Stops scanning of a literal and drop the collected characters,
- // e.g., due to an encountered error.
- inline void DropLiteral() {
- next_.literal_chars = NULL;
- }
-
- inline void AddLiteralCharAdvance() {
- AddLiteralChar(c0_);
- Advance();
- }
-
- // Low-level scanning support.
- void Advance() { c0_ = source_->Advance(); }
- void PushBack(uc32 ch) {
- source_->PushBack(c0_);
- c0_ = ch;
- }
-
- inline Token::Value Select(Token::Value tok) {
- Advance();
- return tok;
- }
-
- inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
- Advance();
- if (c0_ == next) {
- Advance();
- return then;
- } else {
- return else_;
- }
- }
-
- uc32 ScanHexNumber(int expected_length);
-
- // Return the current source position.
- int source_pos() {
- return source_->pos() - kCharacterLookaheadBufferSize;
- }
-
- UnicodeCache* unicode_cache_;
-
- // Buffers collecting literal strings, numbers, etc.
- LiteralBuffer literal_buffer1_;
- LiteralBuffer literal_buffer2_;
-
- TokenDesc current_; // desc for current token (as returned by Next())
- TokenDesc next_; // desc for next token (one token look-ahead)
-
- // Input stream. Must be initialized to an UC16CharacterStream.
- UC16CharacterStream* source_;
-
- // One Unicode character look-ahead; c0_ < 0 at the end of the input.
- uc32 c0_;
-};
-
-// ----------------------------------------------------------------------------
-// JavaScriptScanner - base logic for JavaScript scanning.
-
-class JavaScriptScanner : public Scanner {
- public:
- // A LiteralScope that disables recording of some types of JavaScript
- // literals. If the scanner is configured to not record the specific
- // type of literal, the scope will not call StartLiteral.
- class LiteralScope {
- public:
- explicit LiteralScope(JavaScriptScanner* self)
- : scanner_(self), complete_(false) {
- scanner_->StartLiteral();
- }
- ~LiteralScope() {
- if (!complete_) scanner_->DropLiteral();
- }
- void Complete() {
- scanner_->TerminateLiteral();
- complete_ = true;
- }
-
- private:
- JavaScriptScanner* scanner_;
- bool complete_;
- };
-
- explicit JavaScriptScanner(UnicodeCache* scanner_contants);
-
- void Initialize(UC16CharacterStream* source);
-
- // Returns the next token.
- Token::Value Next();
-
- // Returns true if there was a line terminator before the peek'ed token,
- // possibly inside a multi-line comment.
- bool HasAnyLineTerminatorBeforeNext() const {
- return has_line_terminator_before_next_ ||
- has_multiline_comment_before_next_;
- }
-
- // Scans the input as a regular expression pattern, previous
- // character(s) must be /(=). Returns true if a pattern is scanned.
- bool ScanRegExpPattern(bool seen_equal);
- // Returns true if regexp flags are scanned (always since flags can
- // be empty).
- bool ScanRegExpFlags();
-
- // Tells whether the buffer contains an identifier (no escapes).
- // Used for checking if a property name is an identifier.
- static bool IsIdentifier(unibrow::CharacterStream* buffer);
-
- // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
- uc32 ScanOctalEscape(uc32 c, int length);
-
- // Returns the location of the last seen octal literal
- Location octal_position() const { return octal_pos_; }
- void clear_octal_position() { octal_pos_ = Location::invalid(); }
-
- // Seek forward to the given position. This operation does not
- // work in general, for instance when there are pushed back
- // characters, but works for seeking forward until simple delimiter
- // tokens, which is what it is used for.
- void SeekForward(int pos);
-
- bool HarmonyBlockScoping() const {
- return harmony_block_scoping_;
- }
- void SetHarmonyBlockScoping(bool block_scoping) {
- harmony_block_scoping_ = block_scoping;
- }
-
-
- protected:
- bool SkipWhiteSpace();
- Token::Value SkipSingleLineComment();
- Token::Value SkipMultiLineComment();
-
- // Scans a single JavaScript token.
- void Scan();
-
- void ScanDecimalDigits();
- Token::Value ScanNumber(bool seen_period);
- Token::Value ScanIdentifierOrKeyword();
- Token::Value ScanIdentifierSuffix(LiteralScope* literal);
-
- void ScanEscape();
- Token::Value ScanString();
-
- // Scans a possible HTML comment -- begins with '<!'.
- Token::Value ScanHtmlComment();
-
- // Decodes a unicode escape-sequence which is part of an identifier.
- // If the escape sequence cannot be decoded the result is kBadChar.
- uc32 ScanIdentifierUnicodeEscape();
- // Recognizes a uniocde escape-sequence and adds its characters,
- // uninterpreted, to the current literal. Used for parsing RegExp
- // flags.
- bool ScanLiteralUnicodeEscape();
-
- // Start position of the octal literal last scanned.
- Location octal_pos_;
-
- // Whether there is a line terminator whitespace character after
- // the current token, and before the next. Does not count newlines
- // inside multiline comments.
- bool has_line_terminator_before_next_;
- // Whether there is a multi-line comment that contains a
- // line-terminator after the current token, and before the next.
- bool has_multiline_comment_before_next_;
- // Whether we scan 'let' as a keyword for harmony block scoped
- // let bindings.
- bool harmony_block_scoping_;
-};
-
-} } // namespace v8::internal
-
-#endif // V8_SCANNER_BASE_H_
diff --git a/src/scanner-character-streams.cc b/src/scanner-character-streams.cc
new file mode 100644
index 00000000..ee10703c
--- /dev/null
+++ b/src/scanner-character-streams.cc
@@ -0,0 +1,307 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "scanner-character-streams.h"
+
+#include "handles.h"
+#include "unicode-inl.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// BufferedUC16CharacterStreams
+
+BufferedUC16CharacterStream::BufferedUC16CharacterStream()
+ : UC16CharacterStream(),
+ pushback_limit_(NULL) {
+ // Initialize buffer as being empty. First read will fill the buffer.
+ buffer_cursor_ = buffer_;
+ buffer_end_ = buffer_;
+}
+
+BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
+
+void BufferedUC16CharacterStream::PushBack(uc32 character) {
+ if (character == kEndOfInput) {
+ pos_--;
+ return;
+ }
+ if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
+ // buffer_ is writable, buffer_cursor_ is const pointer.
+ buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
+ pos_--;
+ return;
+ }
+ SlowPushBack(static_cast<uc16>(character));
+}
+
+
+void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
+ // In pushback mode, the end of the buffer contains pushback,
+ // and the start of the buffer (from buffer start to pushback_limit_)
+ // contains valid data that comes just after the pushback.
+ // We NULL the pushback_limit_ if pushing all the way back to the
+ // start of the buffer.
+
+ if (pushback_limit_ == NULL) {
+ // Enter pushback mode.
+ pushback_limit_ = buffer_end_;
+ buffer_end_ = buffer_ + kBufferSize;
+ buffer_cursor_ = buffer_end_;
+ }
+ // Ensure that there is room for at least one pushback.
+ ASSERT(buffer_cursor_ > buffer_);
+ ASSERT(pos_ > 0);
+ buffer_[--buffer_cursor_ - buffer_] = character;
+ if (buffer_cursor_ == buffer_) {
+ pushback_limit_ = NULL;
+ } else if (buffer_cursor_ < pushback_limit_) {
+ pushback_limit_ = buffer_cursor_;
+ }
+ pos_--;
+}
+
+
+bool BufferedUC16CharacterStream::ReadBlock() {
+ buffer_cursor_ = buffer_;
+ if (pushback_limit_ != NULL) {
+ // Leave pushback mode.
+ buffer_end_ = pushback_limit_;
+ pushback_limit_ = NULL;
+ // If there were any valid characters left at the
+ // start of the buffer, use those.
+ if (buffer_cursor_ < buffer_end_) return true;
+ // Otherwise read a new block.
+ }
+ unsigned length = FillBuffer(pos_, kBufferSize);
+ buffer_end_ = buffer_ + length;
+ return length > 0;
+}
+
+
+unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
+ // Leave pushback mode (i.e., ignore that there might be valid data
+ // in the buffer before the pushback_limit_ point).
+ pushback_limit_ = NULL;
+ return BufferSeekForward(delta);
+}
+
+// ----------------------------------------------------------------------------
+// GenericStringUC16CharacterStream
+
+
+GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
+ Handle<String> data,
+ unsigned start_position,
+ unsigned end_position)
+ : string_(data),
+ length_(end_position) {
+ ASSERT(end_position >= start_position);
+ buffer_cursor_ = buffer_;
+ buffer_end_ = buffer_;
+ pos_ = start_position;
+}
+
+
+GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
+
+
+unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
+ unsigned old_pos = pos_;
+ pos_ = Min(pos_ + delta, length_);
+ ReadBlock();
+ return pos_ - old_pos;
+}
+
+
+unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
+ unsigned length) {
+ if (from_pos >= length_) return 0;
+ if (from_pos + length > length_) {
+ length = length_ - from_pos;
+ }
+ String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
+ return length;
+}
+
+
+// ----------------------------------------------------------------------------
+// Utf8ToUC16CharacterStream
+Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
+ unsigned length)
+ : BufferedUC16CharacterStream(),
+ raw_data_(data),
+ raw_data_length_(length),
+ raw_data_pos_(0),
+ raw_character_position_(0) {
+ ReadBlock();
+}
+
+
+Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
+
+
+unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
+ unsigned old_pos = pos_;
+ unsigned target_pos = pos_ + delta;
+ SetRawPosition(target_pos);
+ pos_ = raw_character_position_;
+ ReadBlock();
+ return pos_ - old_pos;
+}
+
+
+unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
+ unsigned length) {
+ static const unibrow::uchar kMaxUC16Character = 0xffff;
+ SetRawPosition(char_position);
+ if (raw_character_position_ != char_position) {
+ // char_position was not a valid position in the stream (hit the end
+ // while spooling to it).
+ return 0u;
+ }
+ unsigned i = 0;
+ while (i < length) {
+ if (raw_data_pos_ == raw_data_length_) break;
+ unibrow::uchar c = raw_data_[raw_data_pos_];
+ if (c <= unibrow::Utf8::kMaxOneByteChar) {
+ raw_data_pos_++;
+ } else {
+ c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
+ raw_data_length_ - raw_data_pos_,
+ &raw_data_pos_);
+ // Don't allow characters outside of the BMP.
+ if (c > kMaxUC16Character) {
+ c = unibrow::Utf8::kBadChar;
+ }
+ }
+ buffer_[i++] = static_cast<uc16>(c);
+ }
+ raw_character_position_ = char_position + i;
+ return i;
+}
+
+
+static const byte kUtf8MultiByteMask = 0xC0;
+static const byte kUtf8MultiByteCharStart = 0xC0;
+static const byte kUtf8MultiByteCharFollower = 0x80;
+
+
+#ifdef DEBUG
+static bool IsUtf8MultiCharacterStart(byte first_byte) {
+ return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
+}
+#endif
+
+
+static bool IsUtf8MultiCharacterFollower(byte later_byte) {
+ return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
+}
+
+
+// Move the cursor back to point at the preceding UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
+ byte character = buffer[--*cursor];
+ if (character > unibrow::Utf8::kMaxOneByteChar) {
+ ASSERT(IsUtf8MultiCharacterFollower(character));
+ // Last byte of a multi-byte character encoding. Step backwards until
+ // pointing to the first byte of the encoding, recognized by having the
+ // top two bits set.
+ while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
+ ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
+ }
+}
+
+
+// Move the cursor forward to point at the next following UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
+ byte character = buffer[(*cursor)++];
+ if (character > unibrow::Utf8::kMaxOneByteChar) {
+ // First character of a multi-byte character encoding.
+ // The number of most-significant one-bits determines the length of the
+ // encoding:
+ // 110..... - (0xCx, 0xDx) one additional byte (minimum).
+ // 1110.... - (0xEx) two additional bytes.
+ // 11110... - (0xFx) three additional bytes (maximum).
+ ASSERT(IsUtf8MultiCharacterStart(character));
+ // Additional bytes is:
+ // 1 if value in range 0xC0 .. 0xDF.
+ // 2 if value in range 0xE0 .. 0xEF.
+ // 3 if value in range 0xF0 .. 0xF7.
+ // Encode that in a single value.
+ unsigned additional_bytes =
+ ((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
+ *cursor += additional_bytes;
+ ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
+ }
+}
+
+
+void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
+ if (raw_character_position_ > target_position) {
+ // Spool backwards in utf8 buffer.
+ do {
+ Utf8CharacterBack(raw_data_, &raw_data_pos_);
+ raw_character_position_--;
+ } while (raw_character_position_ > target_position);
+ return;
+ }
+ // Spool forwards in the utf8 buffer.
+ while (raw_character_position_ < target_position) {
+ if (raw_data_pos_ == raw_data_length_) return;
+ Utf8CharacterForward(raw_data_, &raw_data_pos_);
+ raw_character_position_++;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// ExternalTwoByteStringUC16CharacterStream
+
+ExternalTwoByteStringUC16CharacterStream::
+ ~ExternalTwoByteStringUC16CharacterStream() { }
+
+
+ExternalTwoByteStringUC16CharacterStream
+ ::ExternalTwoByteStringUC16CharacterStream(
+ Handle<ExternalTwoByteString> data,
+ int start_position,
+ int end_position)
+ : UC16CharacterStream(),
+ source_(data),
+ raw_data_(data->GetTwoByteData(start_position)) {
+ buffer_cursor_ = raw_data_,
+ buffer_end_ = raw_data_ + (end_position - start_position);
+ pos_ = start_position;
+}
+
+} } // namespace v8::internal
diff --git a/src/scanner-character-streams.h b/src/scanner-character-streams.h
new file mode 100644
index 00000000..5c4ea2ca
--- /dev/null
+++ b/src/scanner-character-streams.h
@@ -0,0 +1,129 @@
+// Copyright 2011 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.
+
+#ifndef V8_SCANNER_CHARACTER_STREAMS_H_
+#define V8_SCANNER_CHARACTER_STREAMS_H_
+
+#include "scanner.h"
+
+namespace v8 {
+namespace internal {
+
+// A buffered character stream based on a random access character
+// source (ReadBlock can be called with pos_ pointing to any position,
+// even positions before the current).
+class BufferedUC16CharacterStream: public UC16CharacterStream {
+ public:
+ BufferedUC16CharacterStream();
+ virtual ~BufferedUC16CharacterStream();
+
+ virtual void PushBack(uc32 character);
+
+ protected:
+ static const unsigned kBufferSize = 512;
+ static const unsigned kPushBackStepSize = 16;
+
+ virtual unsigned SlowSeekForward(unsigned delta);
+ virtual bool ReadBlock();
+ virtual void SlowPushBack(uc16 character);
+
+ virtual unsigned BufferSeekForward(unsigned delta) = 0;
+ virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
+
+ const uc16* pushback_limit_;
+ uc16 buffer_[kBufferSize];
+};
+
+
+// Generic string stream.
+class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
+ public:
+ GenericStringUC16CharacterStream(Handle<String> data,
+ unsigned start_position,
+ unsigned end_position);
+ virtual ~GenericStringUC16CharacterStream();
+
+ protected:
+ virtual unsigned BufferSeekForward(unsigned delta);
+ virtual unsigned FillBuffer(unsigned position, unsigned length);
+
+ Handle<String> string_;
+ unsigned start_position_;
+ unsigned length_;
+};
+
+
+// UC16 stream based on a literal UTF-8 string.
+class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
+ public:
+ Utf8ToUC16CharacterStream(const byte* data, unsigned length);
+ virtual ~Utf8ToUC16CharacterStream();
+
+ protected:
+ virtual unsigned BufferSeekForward(unsigned delta);
+ virtual unsigned FillBuffer(unsigned char_position, unsigned length);
+ void SetRawPosition(unsigned char_position);
+
+ const byte* raw_data_;
+ unsigned raw_data_length_; // Measured in bytes, not characters.
+ unsigned raw_data_pos_;
+ // The character position of the character at raw_data[raw_data_pos_].
+ // Not necessarily the same as pos_.
+ unsigned raw_character_position_;
+};
+
+
+// UTF16 buffer to read characters from an external string.
+class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
+ public:
+ ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
+ int start_position,
+ int end_position);
+ virtual ~ExternalTwoByteStringUC16CharacterStream();
+
+ virtual void PushBack(uc32 character) {
+ ASSERT(buffer_cursor_ > raw_data_);
+ buffer_cursor_--;
+ pos_--;
+ }
+
+ protected:
+ virtual unsigned SlowSeekForward(unsigned delta) {
+ // Fast case always handles seeking.
+ return 0;
+ }
+ virtual bool ReadBlock() {
+ // Entire string is read at start.
+ return false;
+ }
+ Handle<ExternalTwoByteString> source_;
+ const uc16* raw_data_; // Pointer to the actual array of characters.
+};
+
+} } // namespace v8::internal
+
+#endif // V8_SCANNER_CHARACTER_STREAMS_H_
diff --git a/src/scanner.cc b/src/scanner.cc
index 5919073c..69ea8ae6 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -25,303 +25,1086 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "v8.h"
+// Features shared by parsing and pre-parsing scanners.
-#include "ast.h"
-#include "handles.h"
#include "scanner.h"
-#include "unicode-inl.h"
+
+#include "../include/v8stdint.h"
+#include "char-predicates-inl.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
-// BufferedUC16CharacterStreams
-
-BufferedUC16CharacterStream::BufferedUC16CharacterStream()
- : UC16CharacterStream(),
- pushback_limit_(NULL) {
- // Initialize buffer as being empty. First read will fill the buffer.
- buffer_cursor_ = buffer_;
- buffer_end_ = buffer_;
+// Scanner::LiteralScope
+
+Scanner::LiteralScope::LiteralScope(Scanner* self)
+ : scanner_(self), complete_(false) {
+ self->StartLiteral();
}
-BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
-void BufferedUC16CharacterStream::PushBack(uc32 character) {
- if (character == kEndOfInput) {
- pos_--;
- return;
- }
- if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
- // buffer_ is writable, buffer_cursor_ is const pointer.
- buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
- pos_--;
- return;
- }
- SlowPushBack(static_cast<uc16>(character));
+Scanner::LiteralScope::~LiteralScope() {
+ if (!complete_) scanner_->DropLiteral();
}
-void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
- // In pushback mode, the end of the buffer contains pushback,
- // and the start of the buffer (from buffer start to pushback_limit_)
- // contains valid data that comes just after the pushback.
- // We NULL the pushback_limit_ if pushing all the way back to the
- // start of the buffer.
+void Scanner::LiteralScope::Complete() {
+ scanner_->TerminateLiteral();
+ complete_ = true;
+}
- if (pushback_limit_ == NULL) {
- // Enter pushback mode.
- pushback_limit_ = buffer_end_;
- buffer_end_ = buffer_ + kBufferSize;
- buffer_cursor_ = buffer_end_;
- }
- // Ensure that there is room for at least one pushback.
- ASSERT(buffer_cursor_ > buffer_);
- ASSERT(pos_ > 0);
- buffer_[--buffer_cursor_ - buffer_] = character;
- if (buffer_cursor_ == buffer_) {
- pushback_limit_ = NULL;
- } else if (buffer_cursor_ < pushback_limit_) {
- pushback_limit_ = buffer_cursor_;
+// ----------------------------------------------------------------------------
+// Scanner
+
+Scanner::Scanner(UnicodeCache* unicode_cache)
+ : unicode_cache_(unicode_cache) { }
+
+
+uc32 Scanner::ScanHexNumber(int expected_length) {
+ ASSERT(expected_length <= 4); // prevent overflow
+
+ uc32 digits[4] = { 0, 0, 0, 0 };
+ uc32 x = 0;
+ for (int i = 0; i < expected_length; i++) {
+ digits[i] = c0_;
+ int d = HexValue(c0_);
+ if (d < 0) {
+ // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
+ // should be illegal, but other JS VMs just return the
+ // non-escaped version of the original character.
+
+ // Push back digits that we have advanced past.
+ for (int j = i-1; j >= 0; j--) {
+ PushBack(digits[j]);
+ }
+ return -1;
+ }
+ x = x * 16 + d;
+ Advance();
}
- pos_--;
+
+ return x;
}
-bool BufferedUC16CharacterStream::ReadBlock() {
- buffer_cursor_ = buffer_;
- if (pushback_limit_ != NULL) {
- // Leave pushback mode.
- buffer_end_ = pushback_limit_;
- pushback_limit_ = NULL;
- // If there were any valid characters left at the
- // start of the buffer, use those.
- if (buffer_cursor_ < buffer_end_) return true;
- // Otherwise read a new block.
+
+// ----------------------------------------------------------------------------
+// JavaScriptScanner
+
+JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
+ : Scanner(scanner_contants),
+ octal_pos_(Location::invalid()),
+ harmony_block_scoping_(false) { }
+
+
+void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
+ source_ = source;
+ // Need to capture identifiers in order to recognize "get" and "set"
+ // in object literals.
+ Init();
+ // Skip initial whitespace allowing HTML comment ends just like
+ // after a newline and scan first token.
+ has_line_terminator_before_next_ = true;
+ SkipWhiteSpace();
+ Scan();
+}
+
+
+// Ensure that tokens can be stored in a byte.
+STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
+
+// Table of one-character tokens, by character (0x00..0x7f only).
+static const byte one_char_tokens[] = {
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LPAREN, // 0x28
+ Token::RPAREN, // 0x29
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COMMA, // 0x2c
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COLON, // 0x3a
+ Token::SEMICOLON, // 0x3b
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::CONDITIONAL, // 0x3f
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACK, // 0x5b
+ Token::ILLEGAL,
+ Token::RBRACK, // 0x5d
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACE, // 0x7b
+ Token::ILLEGAL,
+ Token::RBRACE, // 0x7d
+ Token::BIT_NOT, // 0x7e
+ Token::ILLEGAL
+};
+
+
+Token::Value JavaScriptScanner::Next() {
+ current_ = next_;
+ has_line_terminator_before_next_ = false;
+ has_multiline_comment_before_next_ = false;
+ if (static_cast<unsigned>(c0_) <= 0x7f) {
+ Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
+ if (token != Token::ILLEGAL) {
+ int pos = source_pos();
+ next_.token = token;
+ next_.location.beg_pos = pos;
+ next_.location.end_pos = pos + 1;
+ Advance();
+ return current_.token;
+ }
}
- unsigned length = FillBuffer(pos_, kBufferSize);
- buffer_end_ = buffer_ + length;
- return length > 0;
+ Scan();
+ return current_.token;
}
-unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
- // Leave pushback mode (i.e., ignore that there might be valid data
- // in the buffer before the pushback_limit_ point).
- pushback_limit_ = NULL;
- return BufferSeekForward(delta);
+static inline bool IsByteOrderMark(uc32 c) {
+ // The Unicode value U+FFFE is guaranteed never to be assigned as a
+ // Unicode character; this implies that in a Unicode context the
+ // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
+ // character expressed in little-endian byte order (since it could
+ // not be a U+FFFE character expressed in big-endian byte
+ // order). Nevertheless, we check for it to be compatible with
+ // Spidermonkey.
+ return c == 0xFEFF || c == 0xFFFE;
}
-// ----------------------------------------------------------------------------
-// GenericStringUC16CharacterStream
-
-
-GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
- Handle<String> data,
- unsigned start_position,
- unsigned end_position)
- : string_(data),
- length_(end_position) {
- ASSERT(end_position >= start_position);
- buffer_cursor_ = buffer_;
- buffer_end_ = buffer_;
- pos_ = start_position;
+
+bool JavaScriptScanner::SkipWhiteSpace() {
+ int start_position = source_pos();
+
+ while (true) {
+ // We treat byte-order marks (BOMs) as whitespace for better
+ // compatibility with Spidermonkey and other JavaScript engines.
+ while (unicode_cache_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) {
+ // IsWhiteSpace() includes line terminators!
+ if (unicode_cache_->IsLineTerminator(c0_)) {
+ // Ignore line terminators, but remember them. This is necessary
+ // for automatic semicolon insertion.
+ has_line_terminator_before_next_ = true;
+ }
+ Advance();
+ }
+
+ // If there is an HTML comment end '-->' at the beginning of a
+ // line (with only whitespace in front of it), we treat the rest
+ // of the line as a comment. This is in line with the way
+ // SpiderMonkey handles it.
+ if (c0_ == '-' && has_line_terminator_before_next_) {
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '>') {
+ // Treat the rest of the line as a comment.
+ SkipSingleLineComment();
+ // Continue skipping white space after the comment.
+ continue;
+ }
+ PushBack('-'); // undo Advance()
+ }
+ PushBack('-'); // undo Advance()
+ }
+ // Return whether or not we skipped any characters.
+ return source_pos() != start_position;
+ }
}
-GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
+Token::Value JavaScriptScanner::SkipSingleLineComment() {
+ Advance();
+ // The line terminator at the end of the line is not considered
+ // to be part of the single-line comment; it is recognized
+ // separately by the lexical grammar and becomes part of the
+ // stream of input elements for the syntactic grammar (see
+ // ECMA-262, section 7.4).
+ while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+ Advance();
+ }
-unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
- unsigned old_pos = pos_;
- pos_ = Min(pos_ + delta, length_);
- ReadBlock();
- return pos_ - old_pos;
+ return Token::WHITESPACE;
}
-unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
- unsigned length) {
- if (from_pos >= length_) return 0;
- if (from_pos + length > length_) {
- length = length_ - from_pos;
+Token::Value JavaScriptScanner::SkipMultiLineComment() {
+ ASSERT(c0_ == '*');
+ Advance();
+
+ while (c0_ >= 0) {
+ uc32 ch = c0_;
+ Advance();
+ if (unicode_cache_->IsLineTerminator(ch)) {
+ // Following ECMA-262, section 7.4, a comment containing
+ // a newline will make the comment count as a line-terminator.
+ has_multiline_comment_before_next_ = true;
+ }
+ // If we have reached the end of the multi-line comment, we
+ // consume the '/' and insert a whitespace. This way all
+ // multi-line comments are treated as whitespace.
+ if (ch == '*' && c0_ == '/') {
+ c0_ = ' ';
+ return Token::WHITESPACE;
+ }
}
- String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
- return length;
+
+ // Unterminated multi-line comment.
+ return Token::ILLEGAL;
}
-// ----------------------------------------------------------------------------
-// Utf8ToUC16CharacterStream
-Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
- unsigned length)
- : BufferedUC16CharacterStream(),
- raw_data_(data),
- raw_data_length_(length),
- raw_data_pos_(0),
- raw_character_position_(0) {
- ReadBlock();
+Token::Value JavaScriptScanner::ScanHtmlComment() {
+ // Check for <!-- comments.
+ ASSERT(c0_ == '!');
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '-') return SkipSingleLineComment();
+ PushBack('-'); // undo Advance()
+ }
+ PushBack('!'); // undo Advance()
+ ASSERT(c0_ == '!');
+ return Token::LT;
}
-Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
+void JavaScriptScanner::Scan() {
+ next_.literal_chars = NULL;
+ Token::Value token;
+ do {
+ // Remember the position of the next token
+ next_.location.beg_pos = source_pos();
+
+ switch (c0_) {
+ case ' ':
+ case '\t':
+ Advance();
+ token = Token::WHITESPACE;
+ break;
+
+ case '\n':
+ Advance();
+ has_line_terminator_before_next_ = true;
+ token = Token::WHITESPACE;
+ break;
+
+ case '"': case '\'':
+ token = ScanString();
+ break;
+
+ case '<':
+ // < <= << <<= <!--
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::LTE);
+ } else if (c0_ == '<') {
+ token = Select('=', Token::ASSIGN_SHL, Token::SHL);
+ } else if (c0_ == '!') {
+ token = ScanHtmlComment();
+ } else {
+ token = Token::LT;
+ }
+ break;
+
+ case '>':
+ // > >= >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::GTE);
+ } else if (c0_ == '>') {
+ // >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::ASSIGN_SAR);
+ } else if (c0_ == '>') {
+ token = Select('=', Token::ASSIGN_SHR, Token::SHR);
+ } else {
+ token = Token::SAR;
+ }
+ } else {
+ token = Token::GT;
+ }
+ break;
+
+ case '=':
+ // = == ===
+ Advance();
+ if (c0_ == '=') {
+ token = Select('=', Token::EQ_STRICT, Token::EQ);
+ } else {
+ token = Token::ASSIGN;
+ }
+ break;
+
+ case '!':
+ // ! != !==
+ Advance();
+ if (c0_ == '=') {
+ token = Select('=', Token::NE_STRICT, Token::NE);
+ } else {
+ token = Token::NOT;
+ }
+ break;
+
+ case '+':
+ // + ++ +=
+ Advance();
+ if (c0_ == '+') {
+ token = Select(Token::INC);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_ADD);
+ } else {
+ token = Token::ADD;
+ }
+ break;
+
+ case '-':
+ // - -- --> -=
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '>' && has_line_terminator_before_next_) {
+ // For compatibility with SpiderMonkey, we skip lines that
+ // start with an HTML comment end '-->'.
+ token = SkipSingleLineComment();
+ } else {
+ token = Token::DEC;
+ }
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_SUB);
+ } else {
+ token = Token::SUB;
+ }
+ break;
+
+ case '*':
+ // * *=
+ token = Select('=', Token::ASSIGN_MUL, Token::MUL);
+ break;
+ case '%':
+ // % %=
+ token = Select('=', Token::ASSIGN_MOD, Token::MOD);
+ break;
-unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
- unsigned old_pos = pos_;
- unsigned target_pos = pos_ + delta;
- SetRawPosition(target_pos);
- pos_ = raw_character_position_;
- ReadBlock();
- return pos_ - old_pos;
+ case '/':
+ // / // /* /=
+ Advance();
+ if (c0_ == '/') {
+ token = SkipSingleLineComment();
+ } else if (c0_ == '*') {
+ token = SkipMultiLineComment();
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_DIV);
+ } else {
+ token = Token::DIV;
+ }
+ break;
+
+ case '&':
+ // & && &=
+ Advance();
+ if (c0_ == '&') {
+ token = Select(Token::AND);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_BIT_AND);
+ } else {
+ token = Token::BIT_AND;
+ }
+ break;
+
+ case '|':
+ // | || |=
+ Advance();
+ if (c0_ == '|') {
+ token = Select(Token::OR);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_BIT_OR);
+ } else {
+ token = Token::BIT_OR;
+ }
+ break;
+
+ case '^':
+ // ^ ^=
+ token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
+ break;
+
+ case '.':
+ // . Number
+ Advance();
+ if (IsDecimalDigit(c0_)) {
+ token = ScanNumber(true);
+ } else {
+ token = Token::PERIOD;
+ }
+ break;
+
+ case ':':
+ token = Select(Token::COLON);
+ break;
+
+ case ';':
+ token = Select(Token::SEMICOLON);
+ break;
+
+ case ',':
+ token = Select(Token::COMMA);
+ break;
+
+ case '(':
+ token = Select(Token::LPAREN);
+ break;
+
+ case ')':
+ token = Select(Token::RPAREN);
+ break;
+
+ case '[':
+ token = Select(Token::LBRACK);
+ break;
+
+ case ']':
+ token = Select(Token::RBRACK);
+ break;
+
+ case '{':
+ token = Select(Token::LBRACE);
+ break;
+
+ case '}':
+ token = Select(Token::RBRACE);
+ break;
+
+ case '?':
+ token = Select(Token::CONDITIONAL);
+ break;
+
+ case '~':
+ token = Select(Token::BIT_NOT);
+ break;
+
+ default:
+ if (unicode_cache_->IsIdentifierStart(c0_)) {
+ token = ScanIdentifierOrKeyword();
+ } else if (IsDecimalDigit(c0_)) {
+ token = ScanNumber(false);
+ } else if (SkipWhiteSpace()) {
+ token = Token::WHITESPACE;
+ } else if (c0_ < 0) {
+ token = Token::EOS;
+ } else {
+ token = Select(Token::ILLEGAL);
+ }
+ break;
+ }
+
+ // Continue scanning for tokens as long as we're just skipping
+ // whitespace.
+ } while (token == Token::WHITESPACE);
+
+ next_.location.end_pos = source_pos();
+ next_.token = token;
}
-unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
- unsigned length) {
- static const unibrow::uchar kMaxUC16Character = 0xffff;
- SetRawPosition(char_position);
- if (raw_character_position_ != char_position) {
- // char_position was not a valid position in the stream (hit the end
- // while spooling to it).
- return 0u;
+void JavaScriptScanner::SeekForward(int pos) {
+ // After this call, we will have the token at the given position as
+ // the "next" token. The "current" token will be invalid.
+ if (pos == next_.location.beg_pos) return;
+ int current_pos = source_pos();
+ ASSERT_EQ(next_.location.end_pos, current_pos);
+ // Positions inside the lookahead token aren't supported.
+ ASSERT(pos >= current_pos);
+ if (pos != current_pos) {
+ source_->SeekForward(pos - source_->pos());
+ Advance();
+ // This function is only called to seek to the location
+ // of the end of a function (at the "}" token). It doesn't matter
+ // whether there was a line terminator in the part we skip.
+ has_line_terminator_before_next_ = false;
+ has_multiline_comment_before_next_ = false;
}
- unsigned i = 0;
- while (i < length) {
- if (raw_data_pos_ == raw_data_length_) break;
- unibrow::uchar c = raw_data_[raw_data_pos_];
- if (c <= unibrow::Utf8::kMaxOneByteChar) {
- raw_data_pos_++;
- } else {
- c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
- raw_data_length_ - raw_data_pos_,
- &raw_data_pos_);
- // Don't allow characters outside of the BMP.
- if (c > kMaxUC16Character) {
- c = unibrow::Utf8::kBadChar;
- }
+ Scan();
+}
+
+
+void JavaScriptScanner::ScanEscape() {
+ uc32 c = c0_;
+ Advance();
+
+ // Skip escaped newlines.
+ if (unicode_cache_->IsLineTerminator(c)) {
+ // Allow CR+LF newlines in multiline string literals.
+ if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
+ // Allow LF+CR newlines in multiline string literals.
+ if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
+ return;
+ }
+
+ switch (c) {
+ case '\'': // fall through
+ case '"' : // fall through
+ case '\\': break;
+ case 'b' : c = '\b'; break;
+ case 'f' : c = '\f'; break;
+ case 'n' : c = '\n'; break;
+ case 'r' : c = '\r'; break;
+ case 't' : c = '\t'; break;
+ case 'u' : {
+ c = ScanHexNumber(4);
+ if (c < 0) c = 'u';
+ break;
+ }
+ case 'v' : c = '\v'; break;
+ case 'x' : {
+ c = ScanHexNumber(2);
+ if (c < 0) c = 'x';
+ break;
}
- buffer_[i++] = static_cast<uc16>(c);
+ case '0' : // fall through
+ case '1' : // fall through
+ case '2' : // fall through
+ case '3' : // fall through
+ case '4' : // fall through
+ case '5' : // fall through
+ case '6' : // fall through
+ case '7' : c = ScanOctalEscape(c, 2); break;
}
- raw_character_position_ = char_position + i;
- return i;
+
+ // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
+ // should be illegal, but they are commonly handled
+ // as non-escaped characters by JS VMs.
+ AddLiteralChar(c);
}
-static const byte kUtf8MultiByteMask = 0xC0;
-static const byte kUtf8MultiByteCharStart = 0xC0;
-static const byte kUtf8MultiByteCharFollower = 0x80;
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
+ uc32 x = c - '0';
+ int i = 0;
+ for (; i < length; i++) {
+ int d = c0_ - '0';
+ if (d < 0 || d > 7) break;
+ int nx = x * 8 + d;
+ if (nx >= 256) break;
+ x = nx;
+ Advance();
+ }
+ // Anything except '\0' is an octal escape sequence, illegal in strict mode.
+ // Remember the position of octal escape sequences so that an error
+ // can be reported later (in strict mode).
+ // We don't report the error immediately, because the octal escape can
+ // occur before the "use strict" directive.
+ if (c != '0' || i > 0) {
+ octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
+ }
+ return x;
+}
+
+
+Token::Value JavaScriptScanner::ScanString() {
+ uc32 quote = c0_;
+ Advance(); // consume quote
+ LiteralScope literal(this);
+ while (c0_ != quote && c0_ >= 0
+ && !unicode_cache_->IsLineTerminator(c0_)) {
+ uc32 c = c0_;
+ Advance();
+ if (c == '\\') {
+ if (c0_ < 0) return Token::ILLEGAL;
+ ScanEscape();
+ } else {
+ AddLiteralChar(c);
+ }
+ }
+ if (c0_ != quote) return Token::ILLEGAL;
+ literal.Complete();
-#ifdef DEBUG
-static bool IsUtf8MultiCharacterStart(byte first_byte) {
- return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
+ Advance(); // consume quote
+ return Token::STRING;
}
-#endif
-static bool IsUtf8MultiCharacterFollower(byte later_byte) {
- return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
+void JavaScriptScanner::ScanDecimalDigits() {
+ while (IsDecimalDigit(c0_))
+ AddLiteralCharAdvance();
}
-// Move the cursor back to point at the preceding UTF-8 character start
-// in the buffer.
-static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
- byte character = buffer[--*cursor];
- if (character > unibrow::Utf8::kMaxOneByteChar) {
- ASSERT(IsUtf8MultiCharacterFollower(character));
- // Last byte of a multi-byte character encoding. Step backwards until
- // pointing to the first byte of the encoding, recognized by having the
- // top two bits set.
- while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
- ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
+Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
+ ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
+
+ enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
+
+ LiteralScope literal(this);
+ if (seen_period) {
+ // we have already seen a decimal point of the float
+ AddLiteralChar('.');
+ ScanDecimalDigits(); // we know we have at least one digit
+
+ } else {
+ // if the first character is '0' we must check for octals and hex
+ if (c0_ == '0') {
+ int start_pos = source_pos(); // For reporting octal positions.
+ AddLiteralCharAdvance();
+
+ // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
+ if (c0_ == 'x' || c0_ == 'X') {
+ // hex number
+ kind = HEX;
+ AddLiteralCharAdvance();
+ if (!IsHexDigit(c0_)) {
+ // we must have at least one hex digit after 'x'/'X'
+ return Token::ILLEGAL;
+ }
+ while (IsHexDigit(c0_)) {
+ AddLiteralCharAdvance();
+ }
+ } else if ('0' <= c0_ && c0_ <= '7') {
+ // (possible) octal number
+ kind = OCTAL;
+ while (true) {
+ if (c0_ == '8' || c0_ == '9') {
+ kind = DECIMAL;
+ break;
+ }
+ if (c0_ < '0' || '7' < c0_) {
+ // Octal literal finished.
+ octal_pos_ = Location(start_pos, source_pos());
+ break;
+ }
+ AddLiteralCharAdvance();
+ }
+ }
+ }
+
+ // Parse decimal digits and allow trailing fractional part.
+ if (kind == DECIMAL) {
+ ScanDecimalDigits(); // optional
+ if (c0_ == '.') {
+ AddLiteralCharAdvance();
+ ScanDecimalDigits(); // optional
+ }
+ }
}
+
+ // scan exponent, if any
+ if (c0_ == 'e' || c0_ == 'E') {
+ ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
+ if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
+ // scan exponent
+ AddLiteralCharAdvance();
+ if (c0_ == '+' || c0_ == '-')
+ AddLiteralCharAdvance();
+ if (!IsDecimalDigit(c0_)) {
+ // we must have at least one decimal digit after 'e'/'E'
+ return Token::ILLEGAL;
+ }
+ ScanDecimalDigits();
+ }
+
+ // The source character immediately following a numeric literal must
+ // not be an identifier start or a decimal digit; see ECMA-262
+ // section 7.8.3, page 17 (note that we read only one decimal digit
+ // if the value is 0).
+ if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
+ return Token::ILLEGAL;
+
+ literal.Complete();
+
+ return Token::NUMBER;
}
-// Move the cursor forward to point at the next following UTF-8 character start
-// in the buffer.
-static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
- byte character = buffer[(*cursor)++];
- if (character > unibrow::Utf8::kMaxOneByteChar) {
- // First character of a multi-byte character encoding.
- // The number of most-significant one-bits determines the length of the
- // encoding:
- // 110..... - (0xCx, 0xDx) one additional byte (minimum).
- // 1110.... - (0xEx) two additional bytes.
- // 11110... - (0xFx) three additional bytes (maximum).
- ASSERT(IsUtf8MultiCharacterStart(character));
- // Additional bytes is:
- // 1 if value in range 0xC0 .. 0xDF.
- // 2 if value in range 0xE0 .. 0xEF.
- // 3 if value in range 0xF0 .. 0xF7.
- // Encode that in a single value.
- unsigned additional_bytes =
- ((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
- *cursor += additional_bytes;
- ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
+uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
+ Advance();
+ if (c0_ != 'u') return -1;
+ Advance();
+ uc32 result = ScanHexNumber(4);
+ if (result < 0) PushBack('u');
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", Token::BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", Token::CASE) \
+ KEYWORD("catch", Token::CATCH) \
+ KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("const", Token::CONST) \
+ KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", Token::DEBUGGER) \
+ KEYWORD("default", Token::DEFAULT) \
+ KEYWORD("delete", Token::DELETE) \
+ KEYWORD("do", Token::DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", Token::ELSE) \
+ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", Token::FALSE_LITERAL) \
+ KEYWORD("finally", Token::FINALLY) \
+ KEYWORD("for", Token::FOR) \
+ KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", Token::IF) \
+ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("in", Token::IN) \
+ KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", harmony_block_scoping \
+ ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("new", Token::NEW) \
+ KEYWORD("null", Token::NULL_LITERAL) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", Token::RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("switch", Token::SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("this", Token::THIS) \
+ KEYWORD("throw", Token::THROW) \
+ KEYWORD("true", Token::TRUE_LITERAL) \
+ KEYWORD("try", Token::TRY) \
+ KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", Token::VAR) \
+ KEYWORD("void", Token::VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", Token::WHILE) \
+ KEYWORD("with", Token::WITH) \
+ KEYWORD_GROUP('y') \
+ KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
+
+
+static Token::Value KeywordOrIdentifierToken(const char* input,
+ int input_length,
+ bool harmony_block_scoping) {
+ ASSERT(input_length >= 1);
+ const int kMinLength = 2;
+ const int kMaxLength = 10;
+ if (input_length < kMinLength || input_length > kMaxLength) {
+ return Token::IDENTIFIER;
}
+ switch (input[0]) {
+ default:
+#define KEYWORD_GROUP_CASE(ch) \
+ break; \
+ case ch:
+#define KEYWORD(keyword, token) \
+ { \
+ /* 'keyword' is a char array, so sizeof(keyword) is */ \
+ /* strlen(keyword) plus 1 for the NUL char. */ \
+ const int keyword_length = sizeof(keyword) - 1; \
+ STATIC_ASSERT(keyword_length >= kMinLength); \
+ STATIC_ASSERT(keyword_length <= kMaxLength); \
+ if (input_length == keyword_length && \
+ input[1] == keyword[1] && \
+ (keyword_length <= 2 || input[2] == keyword[2]) && \
+ (keyword_length <= 3 || input[3] == keyword[3]) && \
+ (keyword_length <= 4 || input[4] == keyword[4]) && \
+ (keyword_length <= 5 || input[5] == keyword[5]) && \
+ (keyword_length <= 6 || input[6] == keyword[6]) && \
+ (keyword_length <= 7 || input[7] == keyword[7]) && \
+ (keyword_length <= 8 || input[8] == keyword[8]) && \
+ (keyword_length <= 9 || input[9] == keyword[9])) { \
+ return token; \
+ } \
+ }
+ KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
+ }
+ return Token::IDENTIFIER;
}
-void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
- if (raw_character_position_ > target_position) {
- // Spool backwards in utf8 buffer.
- do {
- Utf8CharacterBack(raw_data_, &raw_data_pos_);
- raw_character_position_--;
- } while (raw_character_position_ > target_position);
- return;
+Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
+ ASSERT(unicode_cache_->IsIdentifierStart(c0_));
+ LiteralScope literal(this);
+ // Scan identifier start character.
+ if (c0_ == '\\') {
+ uc32 c = ScanIdentifierUnicodeEscape();
+ // Only allow legal identifier start characters.
+ if (c < 0 ||
+ c == '\\' || // No recursive escapes.
+ !unicode_cache_->IsIdentifierStart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ return ScanIdentifierSuffix(&literal);
}
- // Spool forwards in the utf8 buffer.
- while (raw_character_position_ < target_position) {
- if (raw_data_pos_ == raw_data_length_) return;
- Utf8CharacterForward(raw_data_, &raw_data_pos_);
- raw_character_position_++;
+
+ uc32 first_char = c0_;
+ Advance();
+ AddLiteralChar(first_char);
+
+ // Scan the rest of the identifier characters.
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ != '\\') {
+ uc32 next_char = c0_;
+ Advance();
+ AddLiteralChar(next_char);
+ continue;
+ }
+ // Fallthrough if no longer able to complete keyword.
+ return ScanIdentifierSuffix(&literal);
}
+
+ literal.Complete();
+
+ if (next_.literal_chars->is_ascii()) {
+ Vector<const char> chars = next_.literal_chars->ascii_literal();
+ return KeywordOrIdentifierToken(chars.start(),
+ chars.length(),
+ harmony_block_scoping_);
+ }
+
+ return Token::IDENTIFIER;
}
-// ----------------------------------------------------------------------------
-// ExternalTwoByteStringUC16CharacterStream
-
-ExternalTwoByteStringUC16CharacterStream::
- ~ExternalTwoByteStringUC16CharacterStream() { }
-
-
-ExternalTwoByteStringUC16CharacterStream
- ::ExternalTwoByteStringUC16CharacterStream(
- Handle<ExternalTwoByteString> data,
- int start_position,
- int end_position)
- : UC16CharacterStream(),
- source_(data),
- raw_data_(data->GetTwoByteData(start_position)) {
- buffer_cursor_ = raw_data_,
- buffer_end_ = raw_data_ + (end_position - start_position);
- pos_ = start_position;
+Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
+ // Scan the rest of the identifier characters.
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ == '\\') {
+ uc32 c = ScanIdentifierUnicodeEscape();
+ // Only allow legal identifier part characters.
+ if (c < 0 ||
+ c == '\\' ||
+ !unicode_cache_->IsIdentifierPart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ } else {
+ AddLiteralChar(c0_);
+ Advance();
+ }
+ }
+ literal->Complete();
+
+ return Token::IDENTIFIER;
}
-// ----------------------------------------------------------------------------
-// Scanner::LiteralScope
+bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
+ // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
+ bool in_character_class = false;
-Scanner::LiteralScope::LiteralScope(Scanner* self)
- : scanner_(self), complete_(false) {
- self->StartLiteral();
+ // Previous token is either '/' or '/=', in the second case, the
+ // pattern starts at =.
+ next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
+ next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
+
+ // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
+ // the scanner should pass uninterpreted bodies to the RegExp
+ // constructor.
+ LiteralScope literal(this);
+ if (seen_equal) {
+ AddLiteralChar('=');
+ }
+
+ while (c0_ != '/' || in_character_class) {
+ if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ if (c0_ == '\\') { // Escape sequence.
+ AddLiteralCharAdvance();
+ if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ AddLiteralCharAdvance();
+ // If the escape allows more characters, i.e., \x??, \u????, or \c?,
+ // only "safe" characters are allowed (letters, digits, underscore),
+ // otherwise the escape isn't valid and the invalid character has
+ // its normal meaning. I.e., we can just continue scanning without
+ // worrying whether the following characters are part of the escape
+ // or not, since any '/', '\\' or '[' is guaranteed to not be part
+ // of the escape sequence.
+
+ // TODO(896): At some point, parse RegExps more throughly to capture
+ // octal esacpes in strict mode.
+ } else { // Unescaped character.
+ if (c0_ == '[') in_character_class = true;
+ if (c0_ == ']') in_character_class = false;
+ AddLiteralCharAdvance();
+ }
+ }
+ Advance(); // consume '/'
+
+ literal.Complete();
+
+ return true;
}
-Scanner::LiteralScope::~LiteralScope() {
- if (!complete_) scanner_->DropLiteral();
+bool JavaScriptScanner::ScanLiteralUnicodeEscape() {
+ ASSERT(c0_ == '\\');
+ uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0};
+ Advance();
+ int i = 1;
+ if (c0_ == 'u') {
+ i++;
+ while (i < 6) {
+ Advance();
+ if (!IsHexDigit(c0_)) break;
+ chars_read[i] = c0_;
+ i++;
+ }
+ }
+ if (i < 6) {
+ // Incomplete escape. Undo all advances and return false.
+ while (i > 0) {
+ i--;
+ PushBack(chars_read[i]);
+ }
+ return false;
+ }
+ // Complete escape. Add all chars to current literal buffer.
+ for (int i = 0; i < 6; i++) {
+ AddLiteralChar(chars_read[i]);
+ }
+ return true;
}
-void Scanner::LiteralScope::Complete() {
- scanner_->TerminateLiteral();
- complete_ = true;
+bool JavaScriptScanner::ScanRegExpFlags() {
+ // Scan regular expression flags.
+ LiteralScope literal(this);
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ != '\\') {
+ AddLiteralCharAdvance();
+ } else {
+ if (!ScanLiteralUnicodeEscape()) {
+ break;
+ }
+ }
+ }
+ literal.Complete();
+
+ next_.location.end_pos = source_pos() - 1;
+ return true;
}
} } // namespace v8::internal
diff --git a/src/scanner.h b/src/scanner.h
index e66dd60d..16c3a427 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -25,105 +25,538 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Features shared by parsing and pre-parsing scanners.
+
#ifndef V8_SCANNER_H_
#define V8_SCANNER_H_
+#include "allocation.h"
+#include "char-predicates.h"
+#include "checks.h"
+#include "globals.h"
#include "token.h"
-#include "char-predicates-inl.h"
-#include "scanner-base.h"
+#include "unicode-inl.h"
+#include "utils.h"
namespace v8 {
namespace internal {
-// A buffered character stream based on a random access character
-// source (ReadBlock can be called with pos_ pointing to any position,
-// even positions before the current).
-class BufferedUC16CharacterStream: public UC16CharacterStream {
+// Returns the value (0 .. 15) of a hexadecimal character c.
+// If c is not a legal hexadecimal character, returns a value < 0.
+inline int HexValue(uc32 c) {
+ c -= '0';
+ if (static_cast<unsigned>(c) <= 9) return c;
+ c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
+ if (static_cast<unsigned>(c) <= 5) return c + 10;
+ return -1;
+}
+
+
+// ---------------------------------------------------------------------
+// Buffered stream of characters, using an internal UC16 buffer.
+
+class UC16CharacterStream {
public:
- BufferedUC16CharacterStream();
- virtual ~BufferedUC16CharacterStream();
+ UC16CharacterStream() : pos_(0) { }
+ virtual ~UC16CharacterStream() { }
+
+ // Returns and advances past the next UC16 character in the input
+ // stream. If there are no more characters, it returns a negative
+ // value.
+ inline uc32 Advance() {
+ if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
+ pos_++;
+ return static_cast<uc32>(*(buffer_cursor_++));
+ }
+ // Note: currently the following increment is necessary to avoid a
+ // parser problem! The scanner treats the final kEndOfInput as
+ // a character with a position, and does math relative to that
+ // position.
+ pos_++;
+
+ return kEndOfInput;
+ }
- virtual void PushBack(uc32 character);
+ // Return the current position in the character stream.
+ // Starts at zero.
+ inline unsigned pos() const { return pos_; }
+
+ // Skips forward past the next character_count UC16 characters
+ // in the input, or until the end of input if that comes sooner.
+ // Returns the number of characters actually skipped. If less
+ // than character_count,
+ inline unsigned SeekForward(unsigned character_count) {
+ unsigned buffered_chars =
+ static_cast<unsigned>(buffer_end_ - buffer_cursor_);
+ if (character_count <= buffered_chars) {
+ buffer_cursor_ += character_count;
+ pos_ += character_count;
+ return character_count;
+ }
+ return SlowSeekForward(character_count);
+ }
+
+ // Pushes back the most recently read UC16 character (or negative
+ // value if at end of input), i.e., the value returned by the most recent
+ // call to Advance.
+ // Must not be used right after calling SeekForward.
+ virtual void PushBack(int32_t character) = 0;
protected:
- static const unsigned kBufferSize = 512;
- static const unsigned kPushBackStepSize = 16;
+ static const uc32 kEndOfInput = -1;
+
+ // Ensures that the buffer_cursor_ points to the character at
+ // position pos_ of the input, if possible. If the position
+ // is at or after the end of the input, return false. If there
+ // are more characters available, return true.
+ virtual bool ReadBlock() = 0;
+ virtual unsigned SlowSeekForward(unsigned character_count) = 0;
+
+ const uc16* buffer_cursor_;
+ const uc16* buffer_end_;
+ unsigned pos_;
+};
+
- virtual unsigned SlowSeekForward(unsigned delta);
- virtual bool ReadBlock();
- virtual void SlowPushBack(uc16 character);
+class UnicodeCache {
+// ---------------------------------------------------------------------
+// Caching predicates used by scanners.
+ public:
+ UnicodeCache() {}
+ typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
+
+ StaticResource<Utf8Decoder>* utf8_decoder() {
+ return &utf8_decoder_;
+ }
+
+ bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
+ bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
+ bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
+ bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
- virtual unsigned BufferSeekForward(unsigned delta) = 0;
- virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
+ private:
+ unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
+ unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
+ unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
+ unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+ StaticResource<Utf8Decoder> utf8_decoder_;
- const uc16* pushback_limit_;
- uc16 buffer_[kBufferSize];
+ DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
};
-// Generic string stream.
-class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
+// ----------------------------------------------------------------------------
+// LiteralBuffer - Collector of chars of literals.
+
+class LiteralBuffer {
public:
- GenericStringUC16CharacterStream(Handle<String> data,
- unsigned start_position,
- unsigned end_position);
- virtual ~GenericStringUC16CharacterStream();
+ LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
- protected:
- virtual unsigned BufferSeekForward(unsigned delta);
- virtual unsigned FillBuffer(unsigned position, unsigned length);
+ ~LiteralBuffer() {
+ if (backing_store_.length() > 0) {
+ backing_store_.Dispose();
+ }
+ }
+
+ inline void AddChar(uc16 character) {
+ if (position_ >= backing_store_.length()) ExpandBuffer();
+ if (is_ascii_) {
+ if (character < kMaxAsciiCharCodeU) {
+ backing_store_[position_] = static_cast<byte>(character);
+ position_ += kASCIISize;
+ return;
+ }
+ ConvertToUC16();
+ }
+ *reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
+ position_ += kUC16Size;
+ }
+
+ bool is_ascii() { return is_ascii_; }
+
+ Vector<const uc16> uc16_literal() {
+ ASSERT(!is_ascii_);
+ ASSERT((position_ & 0x1) == 0);
+ return Vector<const uc16>(
+ reinterpret_cast<const uc16*>(backing_store_.start()),
+ position_ >> 1);
+ }
+
+ Vector<const char> ascii_literal() {
+ ASSERT(is_ascii_);
+ return Vector<const char>(
+ reinterpret_cast<const char*>(backing_store_.start()),
+ position_);
+ }
- Handle<String> string_;
- unsigned start_position_;
- unsigned length_;
+ int length() {
+ return is_ascii_ ? position_ : (position_ >> 1);
+ }
+
+ void Reset() {
+ position_ = 0;
+ is_ascii_ = true;
+ }
+
+ private:
+ static const int kInitialCapacity = 16;
+ static const int kGrowthFactory = 4;
+ static const int kMinConversionSlack = 256;
+ static const int kMaxGrowth = 1 * MB;
+ inline int NewCapacity(int min_capacity) {
+ int capacity = Max(min_capacity, backing_store_.length());
+ int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
+ return new_capacity;
+ }
+
+ void ExpandBuffer() {
+ Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
+ memcpy(new_store.start(), backing_store_.start(), position_);
+ backing_store_.Dispose();
+ backing_store_ = new_store;
+ }
+
+ void ConvertToUC16() {
+ ASSERT(is_ascii_);
+ Vector<byte> new_store;
+ int new_content_size = position_ * kUC16Size;
+ if (new_content_size >= backing_store_.length()) {
+ // Ensure room for all currently read characters as UC16 as well
+ // as the character about to be stored.
+ new_store = Vector<byte>::New(NewCapacity(new_content_size));
+ } else {
+ new_store = backing_store_;
+ }
+ char* src = reinterpret_cast<char*>(backing_store_.start());
+ uc16* dst = reinterpret_cast<uc16*>(new_store.start());
+ for (int i = position_ - 1; i >= 0; i--) {
+ dst[i] = src[i];
+ }
+ if (new_store.start() != backing_store_.start()) {
+ backing_store_.Dispose();
+ backing_store_ = new_store;
+ }
+ position_ = new_content_size;
+ is_ascii_ = false;
+ }
+
+ bool is_ascii_;
+ int position_;
+ Vector<byte> backing_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
-// UC16 stream based on a literal UTF-8 string.
-class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
+// ----------------------------------------------------------------------------
+// Scanner base-class.
+
+// Generic functionality used by both JSON and JavaScript scanners.
+class Scanner {
public:
- Utf8ToUC16CharacterStream(const byte* data, unsigned length);
- virtual ~Utf8ToUC16CharacterStream();
+ // -1 is outside of the range of any real source code.
+ static const int kNoOctalLocation = -1;
+
+ typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
+
+ class LiteralScope {
+ public:
+ explicit LiteralScope(Scanner* self);
+ ~LiteralScope();
+ void Complete();
+
+ private:
+ Scanner* scanner_;
+ bool complete_;
+ };
+
+ explicit Scanner(UnicodeCache* scanner_contants);
+
+ // Returns the current token again.
+ Token::Value current_token() { return current_.token; }
+
+ // One token look-ahead (past the token returned by Next()).
+ Token::Value peek() const { return next_.token; }
+
+ struct Location {
+ Location(int b, int e) : beg_pos(b), end_pos(e) { }
+ Location() : beg_pos(0), end_pos(0) { }
+
+ bool IsValid() const {
+ return beg_pos >= 0 && end_pos >= beg_pos;
+ }
+
+ static Location invalid() { return Location(-1, -1); }
+
+ int beg_pos;
+ int end_pos;
+ };
+
+ // Returns the location information for the current token
+ // (the token returned by Next()).
+ Location location() const { return current_.location; }
+ Location peek_location() const { return next_.location; }
+
+ // Returns the literal string, if any, for the current token (the
+ // token returned by Next()). The string is 0-terminated and in
+ // UTF-8 format; they may contain 0-characters. Literal strings are
+ // collected for identifiers, strings, and numbers.
+ // These functions only give the correct result if the literal
+ // was scanned between calls to StartLiteral() and TerminateLiteral().
+ bool is_literal_ascii() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->is_ascii();
+ }
+ Vector<const char> literal_ascii_string() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->ascii_literal();
+ }
+ Vector<const uc16> literal_uc16_string() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->uc16_literal();
+ }
+ int literal_length() const {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->length();
+ }
+
+ bool literal_contains_escapes() const {
+ Location location = current_.location;
+ int source_length = (location.end_pos - location.beg_pos);
+ if (current_.token == Token::STRING) {
+ // Subtract delimiters.
+ source_length -= 2;
+ }
+ return current_.literal_chars->length() != source_length;
+ }
+
+ // Returns the literal string for the next token (the token that
+ // would be returned if Next() were called).
+ bool is_next_literal_ascii() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->is_ascii();
+ }
+ Vector<const char> next_literal_ascii_string() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->ascii_literal();
+ }
+ Vector<const uc16> next_literal_uc16_string() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->uc16_literal();
+ }
+ int next_literal_length() const {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->length();
+ }
+
+ UnicodeCache* unicode_cache() { return unicode_cache_; }
+
+ static const int kCharacterLookaheadBufferSize = 1;
protected:
- virtual unsigned BufferSeekForward(unsigned delta);
- virtual unsigned FillBuffer(unsigned char_position, unsigned length);
- void SetRawPosition(unsigned char_position);
-
- const byte* raw_data_;
- unsigned raw_data_length_; // Measured in bytes, not characters.
- unsigned raw_data_pos_;
- // The character position of the character at raw_data[raw_data_pos_].
- // Not necessarily the same as pos_.
- unsigned raw_character_position_;
+ // The current and look-ahead token.
+ struct TokenDesc {
+ Token::Value token;
+ Location location;
+ LiteralBuffer* literal_chars;
+ };
+
+ // Call this after setting source_ to the input.
+ void Init() {
+ // Set c0_ (one character ahead)
+ STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
+ Advance();
+ // Initialize current_ to not refer to a literal.
+ current_.literal_chars = NULL;
+ }
+
+ // Literal buffer support
+ inline void StartLiteral() {
+ LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
+ &literal_buffer2_ : &literal_buffer1_;
+ free_buffer->Reset();
+ next_.literal_chars = free_buffer;
+ }
+
+ inline void AddLiteralChar(uc32 c) {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ next_.literal_chars->AddChar(c);
+ }
+
+ // Complete scanning of a literal.
+ inline void TerminateLiteral() {
+ // Does nothing in the current implementation.
+ }
+
+ // Stops scanning of a literal and drop the collected characters,
+ // e.g., due to an encountered error.
+ inline void DropLiteral() {
+ next_.literal_chars = NULL;
+ }
+
+ inline void AddLiteralCharAdvance() {
+ AddLiteralChar(c0_);
+ Advance();
+ }
+
+ // Low-level scanning support.
+ void Advance() { c0_ = source_->Advance(); }
+ void PushBack(uc32 ch) {
+ source_->PushBack(c0_);
+ c0_ = ch;
+ }
+
+ inline Token::Value Select(Token::Value tok) {
+ Advance();
+ return tok;
+ }
+
+ inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
+ Advance();
+ if (c0_ == next) {
+ Advance();
+ return then;
+ } else {
+ return else_;
+ }
+ }
+
+ uc32 ScanHexNumber(int expected_length);
+
+ // Return the current source position.
+ int source_pos() {
+ return source_->pos() - kCharacterLookaheadBufferSize;
+ }
+
+ UnicodeCache* unicode_cache_;
+
+ // Buffers collecting literal strings, numbers, etc.
+ LiteralBuffer literal_buffer1_;
+ LiteralBuffer literal_buffer2_;
+
+ TokenDesc current_; // desc for current token (as returned by Next())
+ TokenDesc next_; // desc for next token (one token look-ahead)
+
+ // Input stream. Must be initialized to an UC16CharacterStream.
+ UC16CharacterStream* source_;
+
+ // One Unicode character look-ahead; c0_ < 0 at the end of the input.
+ uc32 c0_;
};
+// ----------------------------------------------------------------------------
+// JavaScriptScanner - base logic for JavaScript scanning.
-// UTF16 buffer to read characters from an external string.
-class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
+class JavaScriptScanner : public Scanner {
public:
- ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
- int start_position,
- int end_position);
- virtual ~ExternalTwoByteStringUC16CharacterStream();
+ // A LiteralScope that disables recording of some types of JavaScript
+ // literals. If the scanner is configured to not record the specific
+ // type of literal, the scope will not call StartLiteral.
+ class LiteralScope {
+ public:
+ explicit LiteralScope(JavaScriptScanner* self)
+ : scanner_(self), complete_(false) {
+ scanner_->StartLiteral();
+ }
+ ~LiteralScope() {
+ if (!complete_) scanner_->DropLiteral();
+ }
+ void Complete() {
+ scanner_->TerminateLiteral();
+ complete_ = true;
+ }
- virtual void PushBack(uc32 character) {
- ASSERT(buffer_cursor_ > raw_data_);
- buffer_cursor_--;
- pos_--;
+ private:
+ JavaScriptScanner* scanner_;
+ bool complete_;
+ };
+
+ explicit JavaScriptScanner(UnicodeCache* scanner_contants);
+
+ void Initialize(UC16CharacterStream* source);
+
+ // Returns the next token.
+ Token::Value Next();
+
+ // Returns true if there was a line terminator before the peek'ed token,
+ // possibly inside a multi-line comment.
+ bool HasAnyLineTerminatorBeforeNext() const {
+ return has_line_terminator_before_next_ ||
+ has_multiline_comment_before_next_;
}
- protected:
- virtual unsigned SlowSeekForward(unsigned delta) {
- // Fast case always handles seeking.
- return 0;
+ // Scans the input as a regular expression pattern, previous
+ // character(s) must be /(=). Returns true if a pattern is scanned.
+ bool ScanRegExpPattern(bool seen_equal);
+ // Returns true if regexp flags are scanned (always since flags can
+ // be empty).
+ bool ScanRegExpFlags();
+
+ // Tells whether the buffer contains an identifier (no escapes).
+ // Used for checking if a property name is an identifier.
+ static bool IsIdentifier(unibrow::CharacterStream* buffer);
+
+ // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
+ uc32 ScanOctalEscape(uc32 c, int length);
+
+ // Returns the location of the last seen octal literal
+ Location octal_position() const { return octal_pos_; }
+ void clear_octal_position() { octal_pos_ = Location::invalid(); }
+
+ // Seek forward to the given position. This operation does not
+ // work in general, for instance when there are pushed back
+ // characters, but works for seeking forward until simple delimiter
+ // tokens, which is what it is used for.
+ void SeekForward(int pos);
+
+ bool HarmonyBlockScoping() const {
+ return harmony_block_scoping_;
}
- virtual bool ReadBlock() {
- // Entire string is read at start.
- return false;
+ void SetHarmonyBlockScoping(bool block_scoping) {
+ harmony_block_scoping_ = block_scoping;
}
- Handle<ExternalTwoByteString> source_;
- const uc16* raw_data_; // Pointer to the actual array of characters.
+
+
+ protected:
+ bool SkipWhiteSpace();
+ Token::Value SkipSingleLineComment();
+ Token::Value SkipMultiLineComment();
+
+ // Scans a single JavaScript token.
+ void Scan();
+
+ void ScanDecimalDigits();
+ Token::Value ScanNumber(bool seen_period);
+ Token::Value ScanIdentifierOrKeyword();
+ Token::Value ScanIdentifierSuffix(LiteralScope* literal);
+
+ void ScanEscape();
+ Token::Value ScanString();
+
+ // Scans a possible HTML comment -- begins with '<!'.
+ Token::Value ScanHtmlComment();
+
+ // Decodes a unicode escape-sequence which is part of an identifier.
+ // If the escape sequence cannot be decoded the result is kBadChar.
+ uc32 ScanIdentifierUnicodeEscape();
+ // Recognizes a uniocde escape-sequence and adds its characters,
+ // uninterpreted, to the current literal. Used for parsing RegExp
+ // flags.
+ bool ScanLiteralUnicodeEscape();
+
+ // Start position of the octal literal last scanned.
+ Location octal_pos_;
+
+ // Whether there is a line terminator whitespace character after
+ // the current token, and before the next. Does not count newlines
+ // inside multiline comments.
+ bool has_line_terminator_before_next_;
+ // Whether there is a multi-line comment that contains a
+ // line-terminator after the current token, and before the next.
+ bool has_multiline_comment_before_next_;
+ // Whether we scan 'let' as a keyword for harmony block scoped
+ // let bindings.
+ bool harmony_block_scoping_;
};
} } // namespace v8::internal
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 0eacc83c..ad31ca47 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -39,12 +39,8 @@ namespace internal {
static int CompareLocal(Variable* const* v, Variable* const* w) {
- Slot* s = (*v)->AsSlot();
- Slot* t = (*w)->AsSlot();
- // We may have rewritten parameters (that are in the arguments object)
- // and which may have a NULL slot... - find a better solution...
- int x = (s != NULL ? s->index() : 0);
- int y = (t != NULL ? t->index() : 0);
+ int x = (*v)->index();
+ int y = (*w)->index();
// Consider sorting them according to type as well?
return x - y;
}
@@ -86,27 +82,24 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
for (int i = 0; i < locals.length(); i++) {
Variable* var = locals[i];
if (var->is_used()) {
- Slot* slot = var->AsSlot();
- if (slot != NULL) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- // explicitly added to parameters_ above - ignore
- break;
-
- case Slot::LOCAL:
- ASSERT(stack_slots_.length() == slot->index());
- stack_slots_.Add(var->name());
- break;
-
- case Slot::CONTEXT:
- heap_locals.Add(var);
- break;
-
- case Slot::LOOKUP:
- // This is currently not used.
- UNREACHABLE();
- break;
- }
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ case Variable::PARAMETER:
+ break;
+
+ case Variable::LOCAL:
+ ASSERT(stack_slots_.length() == var->index());
+ stack_slots_.Add(var->name());
+ break;
+
+ case Variable::CONTEXT:
+ heap_locals.Add(var);
+ break;
+
+ case Variable::LOOKUP:
+ // We don't expect lookup variables in the locals list.
+ UNREACHABLE();
+ break;
}
}
}
@@ -115,9 +108,9 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
if (scope->num_heap_slots() > 0) {
// Add user-defined slots.
for (int i = 0; i < heap_locals.length(); i++) {
- ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
- ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(heap_locals[i]->name());
context_modes_.Add(heap_locals[i]->mode());
@@ -131,18 +124,18 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
// For now, this must happen at the very end because of the
// ordering of the scope info slots and the respective slot indices.
if (scope->is_function_scope()) {
- Variable* var = scope->function();
- if (var != NULL &&
- var->is_used() &&
- var->AsSlot()->type() == Slot::CONTEXT) {
- function_name_ = var->name();
+ VariableProxy* proxy = scope->function();
+ if (proxy != NULL &&
+ proxy->var()->is_used() &&
+ proxy->var()->IsContextSlot()) {
+ function_name_ = proxy->name();
// Note that we must not find the function name in the context slot
// list - instead it must be handled separately in the
// Contexts::Lookup() function. Thus record an empty symbol here so we
// get the correct number of context slots.
- ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
- ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL);
diff --git a/src/scopeinfo.h b/src/scopeinfo.h
index 1c61f111..40c5c8a6 100644
--- a/src/scopeinfo.h
+++ b/src/scopeinfo.h
@@ -156,7 +156,6 @@ class SerializedScopeInfo : public FixedArray {
static SerializedScopeInfo* Empty();
private:
-
inline Object** ContextEntriesAddr();
inline Object** ParameterEntriesAddr();
@@ -187,6 +186,7 @@ class ContextSlotCache {
void Clear();
static const int kNotFound = -2;
+
private:
ContextSlotCache() {
for (int i = 0; i < kLength; ++i) {
diff --git a/src/scopes.cc b/src/scopes.cc
index a76492e0..d5a7a9f9 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -31,7 +31,6 @@
#include "bootstrapper.h"
#include "compiler.h"
-#include "prettyprinter.h"
#include "scopeinfo.h"
#include "allocation-inl.h"
@@ -314,7 +313,7 @@ void Scope::Initialize(bool inside_with) {
Variable::VAR,
false,
Variable::THIS);
- var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
+ var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var;
}
@@ -331,6 +330,35 @@ void Scope::Initialize(bool inside_with) {
}
+Scope* Scope::FinalizeBlockScope() {
+ ASSERT(is_block_scope());
+ ASSERT(temps_.is_empty());
+ ASSERT(params_.is_empty());
+
+ if (num_var_or_const() > 0) return this;
+
+ // Remove this scope from outer scope.
+ for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) {
+ if (outer_scope_->inner_scopes_[i] == this) {
+ outer_scope_->inner_scopes_.Remove(i);
+ break;
+ }
+ }
+
+ // Reparent inner scopes.
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ outer_scope()->AddInnerScope(inner_scopes_[i]);
+ }
+
+ // Move unresolved variables
+ for (int i = 0; i < unresolved_.length(); i++) {
+ outer_scope()->unresolved_.Add(unresolved_[i]);
+ }
+
+ return NULL;
+}
+
+
Variable* Scope::LocalLookup(Handle<String> name) {
Variable* result = variables_.Lookup(name);
if (result != NULL || scope_info_.is_null()) {
@@ -360,7 +388,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
Variable* var =
variables_.Declare(this, name, mode, true, Variable::NORMAL);
- var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
+ var->AllocateTo(Variable::CONTEXT, index);
return var;
}
@@ -378,16 +406,18 @@ Variable* Scope::Lookup(Handle<String> name) {
Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL);
- function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
- return function_;
+ Variable* function_var =
+ new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
+ function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
+ return function_var;
}
-void Scope::DeclareParameter(Handle<String> name) {
+void Scope::DeclareParameter(Handle<String> name, Variable::Mode mode) {
ASSERT(!already_resolved());
ASSERT(is_function_scope());
Variable* var =
- variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
+ variables_.Declare(this, name, mode, true, Variable::NORMAL);
params_.Add(var);
}
@@ -407,7 +437,8 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
Variable* Scope::DeclareGlobal(Handle<String> name) {
ASSERT(is_global_scope());
- return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true,
+ return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL,
+ true,
Variable::NORMAL);
}
@@ -440,8 +471,11 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
Variable* Scope::NewTemporary(Handle<String> name) {
ASSERT(!already_resolved());
- Variable* var =
- new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
+ Variable* var = new Variable(this,
+ name,
+ Variable::TEMPORARY,
+ true,
+ Variable::NORMAL);
temps_.Add(var);
return var;
}
@@ -467,6 +501,28 @@ void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
}
+Declaration* Scope::CheckConflictingVarDeclarations() {
+ int length = decls_.length();
+ for (int i = 0; i < length; i++) {
+ Declaration* decl = decls_[i];
+ if (decl->mode() != Variable::VAR) continue;
+ Handle<String> name = decl->proxy()->name();
+ bool cond = true;
+ for (Scope* scope = decl->scope(); cond ; scope = scope->outer_scope_) {
+ // There is a conflict if there exists a non-VAR binding.
+ Variable* other_var = scope->variables_.Lookup(name);
+ if (other_var != NULL && other_var->mode() != Variable::VAR) {
+ return decl;
+ }
+
+ // Include declaration scope in the iteration but stop after.
+ if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false;
+ }
+ }
+ return NULL;
+}
+
+
template<class Allocator>
void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
// Collect variables in this scope.
@@ -607,22 +663,40 @@ static void Indent(int n, const char* str) {
static void PrintName(Handle<String> name) {
- SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
PrintF("%s", *s);
}
-static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
- if (var->is_used() || var->rewrite() != NULL) {
+static void PrintLocation(Variable* var) {
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ break;
+ case Variable::PARAMETER:
+ PrintF("parameter[%d]", var->index());
+ break;
+ case Variable::LOCAL:
+ PrintF("local[%d]", var->index());
+ break;
+ case Variable::CONTEXT:
+ PrintF("context[%d]", var->index());
+ break;
+ case Variable::LOOKUP:
+ PrintF("lookup");
+ break;
+ }
+}
+
+
+static void PrintVar(int indent, Variable* var) {
+ if (var->is_used() || !var->IsUnallocated()) {
Indent(indent, Variable::Mode2String(var->mode()));
PrintF(" ");
PrintName(var->name());
PrintF("; // ");
- if (var->rewrite() != NULL) {
- PrintF("%s, ", printer->Print(var->rewrite()));
- if (var->is_accessed_from_inner_scope()) PrintF(", ");
- }
+ PrintLocation(var);
if (var->is_accessed_from_inner_scope()) {
+ if (!var->IsUnallocated()) PrintF(", ");
PrintF("inner scope access");
}
PrintF("\n");
@@ -630,10 +704,10 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
}
-static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) {
+static void PrintMap(int indent, VariableMap* map) {
for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value);
- PrintVar(printer, indent, var);
+ PrintVar(indent, var);
}
}
@@ -690,25 +764,24 @@ void Scope::Print(int n) {
PrintF("%d heap slots\n", num_heap_slots_); }
// Print locals.
- PrettyPrinter printer;
Indent(n1, "// function var\n");
if (function_ != NULL) {
- PrintVar(&printer, n1, function_);
+ PrintVar(n1, function_->var());
}
Indent(n1, "// temporary vars\n");
for (int i = 0; i < temps_.length(); i++) {
- PrintVar(&printer, n1, temps_[i]);
+ PrintVar(n1, temps_[i]);
}
Indent(n1, "// local vars\n");
- PrintMap(&printer, n1, &variables_);
+ PrintMap(n1, &variables_);
Indent(n1, "// dynamic vars\n");
if (dynamics_ != NULL) {
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC));
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
}
// Print inner scopes (disable by providing negative n).
@@ -732,7 +805,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// Declare a new non-local.
var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
// Allocate it by giving it a dynamic lookup.
- var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
+ var->AllocateTo(Variable::LOOKUP, -1);
}
return var;
}
@@ -774,7 +847,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
// the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.)
if (function_ != NULL && function_->name().is_identical_to(name)) {
- var = function_;
+ var = function_->var();
} else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(name, true, invalidated_local);
@@ -989,12 +1062,12 @@ bool Scope::HasArgumentsParameter() {
void Scope::AllocateStackSlot(Variable* var) {
- var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
+ var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
}
void Scope::AllocateHeapSlot(Variable* var) {
- var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
+ var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
}
@@ -1040,14 +1113,14 @@ void Scope::AllocateParameterLocals() {
if (MustAllocate(var)) {
if (MustAllocateInContext(var)) {
- ASSERT(var->rewrite() == NULL || var->IsContextSlot());
- if (var->rewrite() == NULL) {
+ ASSERT(var->IsUnallocated() || var->IsContextSlot());
+ if (var->IsUnallocated()) {
AllocateHeapSlot(var);
}
} else {
- ASSERT(var->rewrite() == NULL || var->IsParameter());
- if (var->rewrite() == NULL) {
- var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
+ ASSERT(var->IsUnallocated() || var->IsParameter());
+ if (var->IsUnallocated()) {
+ var->AllocateTo(Variable::PARAMETER, i);
}
}
}
@@ -1057,11 +1130,9 @@ void Scope::AllocateParameterLocals() {
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
- ASSERT(var->rewrite() == NULL ||
- !var->IsVariable(isolate_->factory()->result_symbol()) ||
- var->AsSlot() == NULL ||
- var->AsSlot()->type() != Slot::LOCAL);
- if (var->rewrite() == NULL && MustAllocate(var)) {
+ ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
+ !var->IsStackLocal());
+ if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
AllocateHeapSlot(var);
} else {
@@ -1089,7 +1160,7 @@ void Scope::AllocateNonParameterLocals() {
// because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) {
- AllocateNonParameterLocal(function_);
+ AllocateNonParameterLocal(function_->var());
}
}
diff --git a/src/scopes.h b/src/scopes.h
index c2c41799..2917a63b 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -112,6 +112,11 @@ class Scope: public ZoneObject {
void Initialize(bool inside_with);
+ // Checks if the block scope is redundant, i.e. it does not contain any
+ // block scoped declarations. In that case it is removed from the scope
+ // tree and its children are reparented.
+ Scope* FinalizeBlockScope();
+
// ---------------------------------------------------------------------------
// Declarations
@@ -130,7 +135,7 @@ class Scope: public ZoneObject {
// Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right.
- void DeclareParameter(Handle<String> name);
+ void DeclareParameter(Handle<String> name, Variable::Mode mode);
// Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned.
@@ -182,6 +187,10 @@ class Scope: public ZoneObject {
// Check if the scope has (at least) one illegal redeclaration.
bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
+ // For harmony block scoping mode: Check if the scope has conflicting var
+ // declarations, i.e. a var declaration that has been hoisted from a nested
+ // scope over a let binding of the same name.
+ Declaration* CheckConflictingVarDeclarations();
// ---------------------------------------------------------------------------
// Scope-specific info.
@@ -235,7 +244,7 @@ class Scope: public ZoneObject {
// The variable holding the function literal for named function
// literals, or NULL.
// Only valid for function scopes.
- Variable* function() const {
+ VariableProxy* function() const {
ASSERT(is_function_scope());
return function_;
}
@@ -354,7 +363,7 @@ class Scope: public ZoneObject {
// Convenience variable.
Variable* receiver_;
// Function variable, if any; function scopes only.
- Variable* function_;
+ VariableProxy* function_;
// Convenience variable; function scopes only.
Variable* arguments_;
@@ -435,10 +444,6 @@ class Scope: public ZoneObject {
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
- inline Slot* NewSlot(Variable* var, Slot::Type type, int index) {
- return new(isolate_->zone()) Slot(isolate_, var, type, index);
- }
-
void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope);
diff --git a/src/serialize.cc b/src/serialize.cc
index 094ad20b..ecb480a8 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -240,13 +240,14 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
// Top addresses
const char* AddressNames[] = {
-#define C(name) "Isolate::" #name,
- ISOLATE_ADDRESS_LIST(C)
+#define BUILD_NAME_LITERAL(CamelName, hacker_name) \
+ "Isolate::" #hacker_name "_address",
+ FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL)
NULL
#undef C
};
- for (uint16_t i = 0; i < Isolate::k_isolate_address_count; ++i) {
+ for (uint16_t i = 0; i < Isolate::kIsolateAddressCount; ++i) {
Add(isolate->get_address_from_id((Isolate::AddressId)i),
TOP_ADDRESS, i, AddressNames[i]);
}
diff --git a/src/smart-pointer.h b/src/smart-array-pointer.h
index 0fa8224e..00721c1a 100644
--- a/src/smart-pointer.h
+++ b/src/smart-array-pointer.h
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -25,8 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef V8_SMART_POINTER_H_
-#define V8_SMART_POINTER_H_
+#ifndef V8_SMART_ARRAY_POINTER_H_
+#define V8_SMART_ARRAY_POINTER_H_
namespace v8 {
namespace internal {
@@ -35,75 +35,66 @@ namespace internal {
// A 'scoped array pointer' that calls DeleteArray on its pointer when the
// destructor is called.
template<typename T>
-class SmartPointer {
+class SmartArrayPointer {
public:
+ // Default constructor. Constructs an empty scoped pointer.
+ inline SmartArrayPointer() : p_(NULL) {}
- // Default constructor. Construct an empty scoped pointer.
- inline SmartPointer() : p(NULL) {}
-
-
- // Construct a scoped pointer from a plain one.
- explicit inline SmartPointer(T* pointer) : p(pointer) {}
-
+ // Constructs a scoped pointer from a plain one.
+ explicit inline SmartArrayPointer(T* ptr) : p_(ptr) {}
// Copy constructor removes the pointer from the original to avoid double
// freeing.
- inline SmartPointer(const SmartPointer<T>& rhs) : p(rhs.p) {
- const_cast<SmartPointer<T>&>(rhs).p = NULL;
+ inline SmartArrayPointer(const SmartArrayPointer<T>& rhs) : p_(rhs.p_) {
+ const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
}
-
// When the destructor of the scoped pointer is executed the plain pointer
// is deleted using DeleteArray. This implies that you must allocate with
// NewArray.
- inline ~SmartPointer() { if (p) DeleteArray(p); }
+ inline ~SmartArrayPointer() { if (p_) DeleteArray(p_); }
+ inline T* operator->() const { return p_; }
// You can get the underlying pointer out with the * operator.
- inline T* operator*() { return p; }
-
+ inline T* operator*() { return p_; }
// You can use [n] to index as if it was a plain pointer
inline T& operator[](size_t i) {
- return p[i];
+ return p_[i];
}
// We don't have implicit conversion to a T* since that hinders migration:
// You would not be able to change a method from returning a T* to
- // returning an SmartPointer<T> and then get errors wherever it is used.
+ // returning an SmartArrayPointer<T> and then get errors wherever it is used.
// If you want to take out the plain pointer and don't want it automatically
// deleted then call Detach(). Afterwards, the smart pointer is empty
// (NULL).
inline T* Detach() {
- T* temp = p;
- p = NULL;
+ T* temp = p_;
+ p_ = NULL;
return temp;
}
-
- // Assignment requires an empty (NULL) SmartPointer as the receiver. Like
+ // Assignment requires an empty (NULL) SmartArrayPointer as the receiver. Like
// the copy constructor it removes the pointer in the original to avoid
// double freeing.
- inline SmartPointer& operator=(const SmartPointer<T>& rhs) {
+ inline SmartArrayPointer& operator=(const SmartArrayPointer<T>& rhs) {
ASSERT(is_empty());
- T* tmp = rhs.p; // swap to handle self-assignment
- const_cast<SmartPointer<T>&>(rhs).p = NULL;
- p = tmp;
+ T* tmp = rhs.p_; // swap to handle self-assignment
+ const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
+ p_ = tmp;
return *this;
}
-
- inline bool is_empty() {
- return p == NULL;
- }
-
+ inline bool is_empty() { return p_ == NULL; }
private:
- T* p;
+ T* p_;
};
} } // namespace v8::internal
-#endif // V8_SMART_POINTER_H_
+#endif // V8_SMART_ARRAY_POINTER_H_
diff --git a/src/spaces.h b/src/spaces.h
index 908cd300..f1564967 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1232,8 +1232,8 @@ class PagedSpace : public Space {
// Returns the number of total pages in this space.
int CountTotalPages();
#endif
- private:
+ private:
// Returns a pointer to the page of the relocation pointer.
Page* MCRelocationTopPage() { return TopPageOf(mc_forwarding_info_); }
@@ -1816,7 +1816,6 @@ class FixedSizeFreeList BASE_EMBEDDED {
void MarkNodes();
private:
-
Heap* heap_;
// Available bytes on the free list.
diff --git a/src/splay-tree.h b/src/splay-tree.h
index 0cb9ea84..72231e4d 100644
--- a/src/splay-tree.h
+++ b/src/splay-tree.h
@@ -123,8 +123,8 @@ class SplayTree {
Value value() { return value_; }
Node* left() { return left_; }
Node* right() { return right_; }
- private:
+ private:
friend class SplayTree;
friend class Locator;
Key key_;
@@ -143,6 +143,7 @@ class SplayTree {
Value& value() { return node_->value_; }
void set_value(const Value& value) { node_->value_ = value; }
inline void bind(Node* node) { node_ = node; }
+
private:
Node* node_;
};
@@ -151,7 +152,6 @@ class SplayTree {
void ForEach(Callback* callback);
protected:
-
// Resets tree root. Existing nodes become unreachable.
void ResetRoot() { root_ = NULL; }
@@ -187,7 +187,6 @@ class SplayTree {
void Call(Node* node) { delete node; }
private:
-
DISALLOW_COPY_AND_ASSIGN(NodeDeleter);
};
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 9002593b..8086cf95 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -252,11 +252,11 @@ void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
}
-SmartPointer<const char> StringStream::ToCString() const {
+SmartArrayPointer<const char> StringStream::ToCString() const {
char* str = NewArray<char>(length_ + 1);
memcpy(str, buffer_, length_);
str[length_] = '\0';
- return SmartPointer<const char>(str);
+ return SmartArrayPointer<const char>(str);
}
diff --git a/src/string-stream.h b/src/string-stream.h
index b3f2e0d7..0ba8f52d 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -93,6 +93,7 @@ class FmtElm {
FmtElm(void* value) : type_(POINTER) { // NOLINT
data_.u_pointer_ = value;
}
+
private:
friend class StringStream;
enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE, POINTER };
@@ -142,7 +143,7 @@ class StringStream {
void OutputToStdOut() { OutputToFile(stdout); }
void Log();
Handle<String> ToString();
- SmartPointer<const char> ToCString() const;
+ SmartArrayPointer<const char> ToCString() const;
int length() const { return length_; }
// Object printing support.
diff --git a/src/string.js b/src/string.js
index a70eeade..297105d0 100644
--- a/src/string.js
+++ b/src/string.js
@@ -223,7 +223,7 @@ function StringReplace(search, replace) {
// Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) {
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
- if (IS_FUNCTION(replace)) {
+ if (IS_SPEC_FUNCTION(replace)) {
if (search.global) {
return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
} else {
@@ -250,7 +250,7 @@ function StringReplace(search, replace) {
builder.addSpecialSlice(0, start);
// Compute the string to replace with.
- if (IS_FUNCTION(replace)) {
+ if (IS_SPEC_FUNCTION(replace)) {
var receiver = %GetDefaultReceiver(replace);
builder.add(%_CallFunction(receiver,
search,
@@ -440,13 +440,14 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
i++;
}
} else {
+ var receiver = %GetDefaultReceiver(replace);
while (i < len) {
var elem = res[i];
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
lastMatchInfoOverride = elem;
- var func_result = replace.apply(null, elem);
+ var func_result = %Apply(replace, receiver, elem, 0, elem.length);
res[i] = TO_STRING_INLINE(func_result);
}
i++;
@@ -472,11 +473,11 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
// The number of captures plus one for the match.
var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
var replacement;
+ var receiver = %GetDefaultReceiver(replace);
if (m == 1) {
// No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object.
- var receiver = %GetDefaultReceiver(replace);
replacement =
%_CallFunction(receiver, s, index, subject, replace);
} else {
@@ -487,7 +488,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
parameters[j] = index;
parameters[j + 1] = subject;
- replacement = replace.apply(null, parameters);
+ replacement = %Apply(replace, receiver, parameters, 0, j + 2);
}
result.add(replacement); // The add method converts to string if necessary.
@@ -911,50 +912,47 @@ function ReplaceResultBuilder(str) {
this.special_string = str;
}
-ReplaceResultBuilder.prototype.__proto__ = null;
-
-
-ReplaceResultBuilder.prototype.add = function(str) {
- str = TO_STRING_INLINE(str);
- if (str.length > 0) this.elements.push(str);
-}
-
-
-ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
- var len = end - start;
- if (start < 0 || len <= 0) return;
- if (start < 0x80000 && len < 0x800) {
- this.elements.push((start << 11) | len);
- } else {
- // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
- // so -len is a smi.
+SetUpLockedPrototype(ReplaceResultBuilder,
+ $Array("elements", "special_string"), $Array(
+ "add", function(str) {
+ str = TO_STRING_INLINE(str);
+ if (str.length > 0) this.elements.push(str);
+ },
+ "addSpecialSlice", function(start, end) {
+ var len = end - start;
+ if (start < 0 || len <= 0) return;
+ if (start < 0x80000 && len < 0x800) {
+ this.elements.push((start << 11) | len);
+ } else {
+ // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
+ // so -len is a smi.
+ var elements = this.elements;
+ elements.push(-len);
+ elements.push(start);
+ }
+ },
+ "generate", function() {
var elements = this.elements;
- elements.push(-len);
- elements.push(start);
+ return %StringBuilderConcat(elements, elements.length, this.special_string);
}
-}
-
-
-ReplaceResultBuilder.prototype.generate = function() {
- var elements = this.elements;
- return %StringBuilderConcat(elements, elements.length, this.special_string);
-}
+));
// -------------------------------------------------------------------
-function SetupString() {
- // Setup the constructor property on the String prototype object.
+function SetUpString() {
+ %CheckIsBootstrapping();
+ // Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
- // Setup the non-enumerable functions on the String object.
+ // Set up the non-enumerable functions on the String object.
InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode
));
- // Setup the non-enumerable functions on the String prototype object.
+ // Set up the non-enumerable functions on the String prototype object.
InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf,
"toString", StringToString,
@@ -994,5 +992,4 @@ function SetupString() {
));
}
-
-SetupString();
+SetUpString();
diff --git a/src/strtod.cc b/src/strtod.cc
index 568531ef..c89c8f33 100644
--- a/src/strtod.cc
+++ b/src/strtod.cc
@@ -27,8 +27,9 @@
#include <stdarg.h>
#include <math.h>
+#include <limits>
-#include "platform.h"
+#include "globals.h"
#include "utils.h"
#include "strtod.h"
#include "bignum.h"
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 13b0b633..55963303 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -74,7 +74,7 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
// the bits are the least significant so they will be the ones
// masked out.
ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
- ASSERT(Code::kFlagsICStateShift == 0);
+ STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
// Make sure that the code type is not included in the hash.
ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
@@ -652,7 +652,6 @@ MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
(kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
MaybeObject* StubCache::ComputeCallConstant(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -678,7 +677,6 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
CONSTANT_FUNCTION,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
@@ -688,8 +686,7 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
// caches.
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallConstant(object, holder, function, name, check);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -711,7 +708,6 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
MaybeObject* StubCache::ComputeCallField(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -734,12 +730,10 @@ MaybeObject* StubCache::ComputeCallField(int argc,
FIELD,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallField(JSObject::cast(object),
holder,
@@ -785,12 +779,10 @@ MaybeObject* StubCache::ComputeCallInterceptor(
INTERCEPTOR,
extra_ic_state,
cache_holder,
- NOT_IN_LOOP,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(
- argc, NOT_IN_LOOP, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -811,14 +803,12 @@ MaybeObject* StubCache::ComputeCallInterceptor(
MaybeObject* StubCache::ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
JSObject* receiver) {
Object* code;
- { MaybeObject* maybe_code =
- ComputeCallNormal(argc, in_loop, kind, extra_ic_state);
+ { MaybeObject* maybe_code = ComputeCallNormal(argc, kind, extra_ic_state);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
return code;
@@ -826,7 +816,6 @@ MaybeObject* StubCache::ComputeCallNormal(int argc,
MaybeObject* StubCache::ComputeCallGlobal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -841,7 +830,6 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
NORMAL,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
@@ -850,8 +838,7 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
// internal error which will make sure we do not update any
// caches.
if (!function->is_compiled()) return Failure::InternalError();
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallGlobal(receiver, holder, cell, function, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -920,14 +907,12 @@ static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
Code* StubCache::FindCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind) {
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
UNINITIALIZED,
extra_state,
NORMAL,
@@ -941,14 +926,12 @@ Code* StubCache::FindCallInitialize(int argc,
MaybeObject* StubCache::ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind) {
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
UNINITIALIZED,
extra_state,
NORMAL,
@@ -964,49 +947,26 @@ MaybeObject* StubCache::ComputeCallInitialize(int argc,
Handle<Code> StubCache::ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode) {
- if (in_loop == IN_LOOP) {
- // Force the creation of the corresponding stub outside loops,
- // because it may be used when clearing the ICs later - it is
- // possible for a series of IC transitions to lose the in-loop
- // information, and the IC clearing code can't generate a stub
- // that it needs so we need to ensure it is generated already.
- ComputeCallInitialize(argc, NOT_IN_LOOP, mode);
- }
CALL_HEAP_FUNCTION(isolate_,
- ComputeCallInitialize(argc, in_loop, mode, Code::CALL_IC),
+ ComputeCallInitialize(argc, mode, Code::CALL_IC),
Code);
}
-Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
- InLoopFlag in_loop) {
- if (in_loop == IN_LOOP) {
- // Force the creation of the corresponding stub outside loops,
- // because it may be used when clearing the ICs later - it is
- // possible for a series of IC transitions to lose the in-loop
- // information, and the IC clearing code can't generate a stub
- // that it needs so we need to ensure it is generated already.
- ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
- }
+Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
CALL_HEAP_FUNCTION(
isolate_,
- ComputeCallInitialize(argc,
- in_loop,
- RelocInfo::CODE_TARGET,
- Code::KEYED_CALL_IC),
+ ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC),
Code);
}
MaybeObject* StubCache::ComputeCallPreMonomorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
PREMONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1022,11 +982,9 @@ MaybeObject* StubCache::ComputeCallPreMonomorphic(
MaybeObject* StubCache::ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1041,12 +999,9 @@ MaybeObject* StubCache::ComputeCallNormal(int argc,
}
-MaybeObject* StubCache::ComputeCallArguments(int argc,
- InLoopFlag in_loop,
- Code::Kind kind) {
+MaybeObject* StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
ASSERT(kind == Code::KEYED_CALL_IC);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MEGAMORPHIC,
Code::kNoExtraICState,
NORMAL,
@@ -1063,11 +1018,9 @@ MaybeObject* StubCache::ComputeCallArguments(int argc,
MaybeObject* StubCache::ComputeCallMegamorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MEGAMORPHIC,
extra_ic_state,
NORMAL,
@@ -1088,7 +1041,6 @@ MaybeObject* StubCache::ComputeCallMiss(int argc,
// MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
// and monomorphic stubs are not mixed up together in the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC_PROTOTYPE_FAILURE,
extra_ic_state,
NORMAL,
@@ -1111,7 +1063,6 @@ MaybeObject* StubCache::ComputeCallDebugBreak(
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
DEBUG_BREAK,
Code::kNoExtraICState,
NORMAL,
@@ -1132,7 +1083,6 @@ MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
DEBUG_PREPARE_STEP_IN,
Code::kNoExtraICState,
NORMAL,
@@ -1672,7 +1622,7 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
String* name,
InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_LOAD_IC, NOT_IN_LOOP, state, Code::kNoExtraICState, type);
+ Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1688,8 +1638,8 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::STORE_IC, type, strict_mode_);
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1707,8 +1657,8 @@ MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
String* name,
InlineCacheState state) {
- Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_STORE_IC, NOT_IN_LOOP, state, strict_mode_, type);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::KEYED_STORE_IC, state, strict_mode_, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1730,12 +1680,10 @@ void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
CallStubCompiler::CallStubCompiler(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder)
: arguments_(argc),
- in_loop_(in_loop),
kind_(kind),
extra_ic_state_(extra_ic_state),
cache_holder_(cache_holder) {
@@ -1796,7 +1744,6 @@ MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
type,
extra_ic_state_,
cache_holder_,
- in_loop_,
argc);
return GetCodeWithFlags(flags, name);
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index dd06a1c0..18c157b1 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -194,7 +194,6 @@ class StubCache {
MUST_USE_RESULT MaybeObject* ComputeCallField(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -204,7 +203,6 @@ class StubCache {
MUST_USE_RESULT MaybeObject* ComputeCallConstant(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -214,7 +212,6 @@ class StubCache {
MUST_USE_RESULT MaybeObject* ComputeCallNormal(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -230,7 +227,6 @@ class StubCache {
MUST_USE_RESULT MaybeObject* ComputeCallGlobal(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -242,33 +238,27 @@ class StubCache {
// ---
MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind);
Handle<Code> ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode);
- Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
+ Handle<Code> ComputeKeyedCallInitialize(int argc);
MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state);
MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState state);
MUST_USE_RESULT MaybeObject* ComputeCallArguments(int argc,
- InLoopFlag in_loop,
Code::Kind kind);
MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState state);
@@ -278,7 +268,6 @@ class StubCache {
// Finds the Code object stored in the Heap::non_monomorphic_cache().
MUST_USE_RESULT Code* FindCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind);
@@ -379,11 +368,7 @@ class StubCache {
// Use the seed from the primary cache in the secondary cache.
uint32_t string_low32bits =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
- // We always set the in_loop bit to zero when generating the lookup code
- // so do it here too so the hash codes match.
- uint32_t iflags =
- (static_cast<uint32_t>(flags) & ~Code::kFlagsICInLoopMask);
- uint32_t key = seed - string_low32bits + iflags;
+ uint32_t key = seed - string_low32bits + flags;
return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
}
@@ -660,7 +645,7 @@ class KeyedLoadStubCompiler: public StubCompiler {
CodeList* handler_ics);
static void GenerateLoadExternalArray(MacroAssembler* masm,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
static void GenerateLoadFastElement(MacroAssembler* masm);
@@ -725,7 +710,7 @@ class KeyedStoreStubCompiler: public StubCompiler {
bool is_js_array);
static void GenerateStoreExternalArray(MacroAssembler* masm,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
static void GenerateStoreDictionaryElement(MacroAssembler* masm);
@@ -755,7 +740,6 @@ class CallOptimization;
class CallStubCompiler: public StubCompiler {
public:
CallStubCompiler(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder);
@@ -815,7 +799,6 @@ class CallStubCompiler: public StubCompiler {
String* name);
const ParameterCount arguments_;
- const InLoopFlag in_loop_;
const Code::Kind kind_;
const Code::ExtraICState extra_ic_state_;
const InlineCacheHolderFlag cache_holder_;
diff --git a/src/type-info.cc b/src/type-info.cc
index bdf7bc3c..c64368e5 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -190,7 +190,6 @@ void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
NORMAL,
extra_ic_state,
OWN_MAP,
- NOT_IN_LOOP,
arity);
CollectReceiverTypes(expr->id(), name, flags, types);
}
diff --git a/src/uri.js b/src/uri.js
index 72ca6f15..c910d756 100644
--- a/src/uri.js
+++ b/src/uri.js
@@ -392,8 +392,9 @@ function URIUnescape(str) {
// -------------------------------------------------------------------
-function SetupURI() {
- // Setup non-enumerable URI functions on the global object and set
+function SetUpUri() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable URI functions on the global object and set
// their names.
InstallFunctions(global, DONT_ENUM, $Array(
"escape", URIEscape,
@@ -405,4 +406,4 @@ function SetupURI() {
));
}
-SetupURI();
+SetUpUri();
diff --git a/src/utils.h b/src/utils.h
index 785bc437..26c522b8 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -203,16 +203,17 @@ inline int StrLength(const char* string) {
template<class T, int shift, int size>
class BitField {
public:
+ // A uint32_t mask of bit field. To use all bits of a uint32 in a
+ // bitfield without compiler warnings we have to compute 2^32 without
+ // using a shift count of 32.
+ static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
+
+ // Value for the field with all bits set.
+ static const T kMax = static_cast<T>((1U << size) - 1);
+
// Tells whether the provided value fits into the bit field.
static bool is_valid(T value) {
- return (static_cast<uint32_t>(value) & ~((1U << (size)) - 1)) == 0;
- }
-
- // Returns a uint32_t mask of bit field.
- static uint32_t mask() {
- // To use all bits of a uint32 in a bitfield without compiler warnings we
- // have to compute 2^32 without using a shift count of 32.
- return ((1U << shift) << size) - (1U << shift);
+ return (static_cast<uint32_t>(value) & ~static_cast<uint32_t>(kMax)) == 0;
}
// Returns a uint32_t with the bit field value encoded.
@@ -223,17 +224,12 @@ class BitField {
// Returns a uint32_t with the bit field value updated.
static uint32_t update(uint32_t previous, T value) {
- return (previous & ~mask()) | encode(value);
+ return (previous & ~kMask) | encode(value);
}
// Extracts the bit field from the value.
static T decode(uint32_t value) {
- return static_cast<T>((value & mask()) >> shift);
- }
-
- // Value for the field with all bits set.
- static T max() {
- return decode(mask());
+ return static_cast<T>((value & kMask) >> shift);
}
};
@@ -497,9 +493,6 @@ class Collector {
public:
explicit Collector(int initial_capacity = kMinCapacity)
: index_(0), size_(0) {
- if (initial_capacity < kMinCapacity) {
- initial_capacity = kMinCapacity;
- }
current_chunk_ = Vector<T>::New(initial_capacity);
}
@@ -601,25 +594,23 @@ class Collector {
// Creates a new current chunk, and stores the old chunk in the chunks_ list.
void Grow(int min_capacity) {
ASSERT(growth_factor > 1);
- int growth = current_chunk_.length() * (growth_factor - 1);
- if (growth > max_growth) {
- growth = max_growth;
- }
- int new_capacity = current_chunk_.length() + growth;
- if (new_capacity < min_capacity) {
- new_capacity = min_capacity + growth;
- }
- Vector<T> new_chunk = Vector<T>::New(new_capacity);
- int new_index = PrepareGrow(new_chunk);
- if (index_ > 0) {
- chunks_.Add(current_chunk_.SubVector(0, index_));
+ int new_capacity;
+ int current_length = current_chunk_.length();
+ if (current_length < kMinCapacity) {
+ // The collector started out as empty.
+ new_capacity = min_capacity * growth_factor;
+ if (new_capacity < kMinCapacity) new_capacity = kMinCapacity;
} else {
- // Can happen if the call to PrepareGrow moves everything into
- // the new chunk.
- current_chunk_.Dispose();
+ int growth = current_length * (growth_factor - 1);
+ if (growth > max_growth) {
+ growth = max_growth;
+ }
+ new_capacity = current_length + growth;
+ if (new_capacity < min_capacity) {
+ new_capacity = min_capacity + growth;
+ }
}
- current_chunk_ = new_chunk;
- index_ = new_index;
+ NewChunk(new_capacity);
ASSERT(index_ + min_capacity <= current_chunk_.length());
}
@@ -627,8 +618,15 @@ class Collector {
// some of the current data into the new chunk. The function may update
// the current index_ value to represent data no longer in the current chunk.
// Returns the initial index of the new chunk (after copied data).
- virtual int PrepareGrow(Vector<T> new_chunk) {
- return 0;
+ virtual void NewChunk(int new_capacity) {
+ Vector<T> new_chunk = Vector<T>::New(new_capacity);
+ if (index_ > 0) {
+ chunks_.Add(current_chunk_.SubVector(0, index_));
+ } else {
+ current_chunk_.Dispose();
+ }
+ current_chunk_ = new_chunk;
+ index_ = 0;
}
};
@@ -683,20 +681,26 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> {
int sequence_start_;
// Move the currently active sequence to the new chunk.
- virtual int PrepareGrow(Vector<T> new_chunk) {
- if (sequence_start_ != kNoSequence) {
- int sequence_length = this->index_ - sequence_start_;
- // The new chunk is always larger than the current chunk, so there
- // is room for the copy.
- ASSERT(sequence_length < new_chunk.length());
- for (int i = 0; i < sequence_length; i++) {
- new_chunk[i] = this->current_chunk_[sequence_start_ + i];
- }
- this->index_ = sequence_start_;
- sequence_start_ = 0;
- return sequence_length;
+ virtual void NewChunk(int new_capacity) {
+ if (sequence_start_ == kNoSequence) {
+ // Fall back on default behavior if no sequence has been started.
+ this->Collector<T, growth_factor, max_growth>::NewChunk(new_capacity);
+ return;
}
- return 0;
+ int sequence_length = this->index_ - sequence_start_;
+ Vector<T> new_chunk = Vector<T>::New(sequence_length + new_capacity);
+ ASSERT(sequence_length < new_chunk.length());
+ for (int i = 0; i < sequence_length; i++) {
+ new_chunk[i] = this->current_chunk_[sequence_start_ + i];
+ }
+ if (sequence_start_ > 0) {
+ this->chunks_.Add(this->current_chunk_.SubVector(0, sequence_start_));
+ } else {
+ this->current_chunk_.Dispose();
+ }
+ this->current_chunk_ = new_chunk;
+ this->index_ = sequence_length;
+ sequence_start_ = 0;
}
};
@@ -882,6 +886,7 @@ class SimpleStringBuilder {
int position_;
bool is_finalized() const { return position_ < 0; }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder);
};
diff --git a/src/v8conversions.cc b/src/v8conversions.cc
index 96056ecf..bf175e50 100644
--- a/src/v8conversions.cc
+++ b/src/v8conversions.cc
@@ -34,7 +34,6 @@
#include "v8conversions.h"
#include "dtoa.h"
#include "factory.h"
-#include "scanner-base.h"
#include "strtod.h"
namespace v8 {
diff --git a/src/v8globals.h b/src/v8globals.h
index f05a702e..eb5c49d7 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -98,6 +98,10 @@ const int kPageSizeBits = 13;
const int kProcessorCacheLineSize = 64;
// Constants relevant to double precision floating point numbers.
+
+// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
+// other bits set.
+const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
// If looking only at the top 32 bits, the QNaN mask is bits 19 to 30.
const uint32_t kQuietNaNHighBitsMask = 0xfff << (51 - 32);
@@ -298,12 +302,6 @@ enum CheckType {
};
-enum InLoopFlag {
- NOT_IN_LOOP,
- IN_LOOP
-};
-
-
enum CallFunctionFlags {
NO_CALL_FUNCTION_FLAGS = 0,
// Receiver might implicitly be the global objects. If it is, the
@@ -330,7 +328,7 @@ enum PropertyType {
HANDLER = 4, // only in lookup results, not in descriptors
INTERCEPTOR = 5, // only in lookup results, not in descriptors
MAP_TRANSITION = 6, // only in fast mode
- EXTERNAL_ARRAY_TRANSITION = 7,
+ ELEMENTS_TRANSITION = 7,
CONSTANT_TRANSITION = 8, // only in fast mode
NULL_DESCRIPTOR = 9, // only in fast mode
// All properties before MAP_TRANSITION are real.
diff --git a/src/v8natives.js b/src/v8natives.js
index 982e18e4..588bdb21 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -41,7 +41,6 @@
const $isNaN = GlobalIsNaN;
const $isFinite = GlobalIsFinite;
-
// ----------------------------------------------------------------------------
@@ -66,28 +65,56 @@ function InstallFunctions(object, attributes, functions) {
// functions on String.prototype etc. and then restore the old function
// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
+ %CheckIsBootstrapping();
var hidden_prototype = new $Object();
%SetHiddenPrototype(object, hidden_prototype);
InstallFunctions(hidden_prototype, attributes, functions);
}
+// Prevents changes to the prototype of a built-infunction.
+// The "prototype" property of the function object is made non-configurable,
+// and the prototype object is made non-extensible. The latter prevents
+// changing the __proto__ property.
+function SetUpLockedPrototype(constructor, fields, methods) {
+ %CheckIsBootstrapping();
+ var prototype = constructor.prototype;
+ // Install functions first, because this function is used to initialize
+ // PropertyDescriptor itself.
+ var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
+ if (property_count >= 4) {
+ %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
+ }
+ if (fields) {
+ for (var i = 0; i < fields.length; i++) {
+ %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
+ }
+ }
+ for (var i = 0; i < methods.length; i += 2) {
+ var key = methods[i];
+ var f = methods[i + 1];
+ %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetNativeFlag(f);
+ }
+ prototype.__proto__ = null;
+ %ToFastProperties(prototype);
+}
+
+
// ----------------------------------------------------------------------------
// ECMA 262 - 15.1.4
function GlobalIsNaN(number) {
- var n = ToNumber(number);
- return NUMBER_IS_NAN(n);
+ if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
+ return NUMBER_IS_NAN(number);
}
// ECMA 262 - 15.1.5
function GlobalIsFinite(number) {
if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
-
- // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
- return %_IsSmi(number) || number - number == 0;
+ return NUMBER_IS_FINITE(number);
}
@@ -162,8 +189,9 @@ function GlobalEval(x) {
// ----------------------------------------------------------------------------
-
-function SetupGlobal() {
+// Set up global object.
+function SetUpGlobal() {
+ %CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
@@ -173,7 +201,7 @@ function SetupGlobal() {
// ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
- // Setup non-enumerable function on the global object.
+ // Set up non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite,
@@ -183,8 +211,7 @@ function SetupGlobal() {
));
}
-SetupGlobal();
-
+SetUpGlobal();
// ----------------------------------------------------------------------------
// Boolean (first part of definition)
@@ -271,7 +298,7 @@ function ObjectDefineGetter(name, fun) {
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
receiver = %GlobalReceiver(global);
}
- if (!IS_FUNCTION(fun)) {
+ if (!IS_SPEC_FUNCTION(fun)) {
throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
}
var desc = new PropertyDescriptor();
@@ -296,7 +323,7 @@ function ObjectDefineSetter(name, fun) {
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
receiver = %GlobalReceiver(global);
}
- if (!IS_FUNCTION(fun)) {
+ if (!IS_SPEC_FUNCTION(fun)) {
throw new $TypeError(
'Object.prototype.__defineSetter__: Expecting function');
}
@@ -426,7 +453,7 @@ function ToPropertyDescriptor(obj) {
if ("get" in obj) {
var get = obj.get;
- if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
+ if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
throw MakeTypeError("getter_must_be_callable", [get]);
}
desc.setGet(get);
@@ -434,7 +461,7 @@ function ToPropertyDescriptor(obj) {
if ("set" in obj) {
var set = obj.set;
- if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
+ if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
throw MakeTypeError("setter_must_be_callable", [set]);
}
desc.setSet(set);
@@ -481,106 +508,83 @@ function PropertyDescriptor() {
this.hasSetter_ = false;
}
-PropertyDescriptor.prototype.__proto__ = null;
-
-PropertyDescriptor.prototype.toString = function() {
- return "[object PropertyDescriptor]";
-};
-
-PropertyDescriptor.prototype.setValue = function(value) {
- this.value_ = value;
- this.hasValue_ = true;
-}
-
-
-PropertyDescriptor.prototype.getValue = function() {
- return this.value_;
-}
-
-
-PropertyDescriptor.prototype.hasValue = function() {
- return this.hasValue_;
-}
-
-
-PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
- this.enumerable_ = enumerable;
- this.hasEnumerable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isEnumerable = function () {
- return this.enumerable_;
-}
-
-
-PropertyDescriptor.prototype.hasEnumerable = function() {
- return this.hasEnumerable_;
-}
-
-
-PropertyDescriptor.prototype.setWritable = function(writable) {
- this.writable_ = writable;
- this.hasWritable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isWritable = function() {
- return this.writable_;
-}
-
-
-PropertyDescriptor.prototype.hasWritable = function() {
- return this.hasWritable_;
-}
-
-
-PropertyDescriptor.prototype.setConfigurable = function(configurable) {
- this.configurable_ = configurable;
- this.hasConfigurable_ = true;
-}
-
-
-PropertyDescriptor.prototype.hasConfigurable = function() {
- return this.hasConfigurable_;
-}
-
-
-PropertyDescriptor.prototype.isConfigurable = function() {
- return this.configurable_;
-}
-
-
-PropertyDescriptor.prototype.setGet = function(get) {
- this.get_ = get;
- this.hasGetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getGet = function() {
- return this.get_;
-}
-
-
-PropertyDescriptor.prototype.hasGetter = function() {
- return this.hasGetter_;
-}
-
-
-PropertyDescriptor.prototype.setSet = function(set) {
- this.set_ = set;
- this.hasSetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getSet = function() {
- return this.set_;
-}
-
-
-PropertyDescriptor.prototype.hasSetter = function() {
- return this.hasSetter_;
-}
+SetUpLockedPrototype(PropertyDescriptor, $Array(
+ "value_",
+ "hasValue_",
+ "writable_",
+ "hasWritable_",
+ "enumerable_",
+ "hasEnumerable_",
+ "configurable_",
+ "hasConfigurable_",
+ "get_",
+ "hasGetter_",
+ "set_",
+ "hasSetter_"
+ ), $Array(
+ "toString", function() {
+ return "[object PropertyDescriptor]";
+ },
+ "setValue", function(value) {
+ this.value_ = value;
+ this.hasValue_ = true;
+ },
+ "getValue", function() {
+ return this.value_;
+ },
+ "hasValue", function() {
+ return this.hasValue_;
+ },
+ "setEnumerable", function(enumerable) {
+ this.enumerable_ = enumerable;
+ this.hasEnumerable_ = true;
+ },
+ "isEnumerable", function () {
+ return this.enumerable_;
+ },
+ "hasEnumerable", function() {
+ return this.hasEnumerable_;
+ },
+ "setWritable", function(writable) {
+ this.writable_ = writable;
+ this.hasWritable_ = true;
+ },
+ "isWritable", function() {
+ return this.writable_;
+ },
+ "hasWritable", function() {
+ return this.hasWritable_;
+ },
+ "setConfigurable", function(configurable) {
+ this.configurable_ = configurable;
+ this.hasConfigurable_ = true;
+ },
+ "hasConfigurable", function() {
+ return this.hasConfigurable_;
+ },
+ "isConfigurable", function() {
+ return this.configurable_;
+ },
+ "setGet", function(get) {
+ this.get_ = get;
+ this.hasGetter_ = true;
+ },
+ "getGet", function() {
+ return this.get_;
+ },
+ "hasGetter", function() {
+ return this.hasGetter_;
+ },
+ "setSet", function(set) {
+ this.set_ = set;
+ this.hasSetter_ = true;
+ },
+ "getSet", function() {
+ return this.set_;
+ },
+ "hasSetter", function() {
+ return this.hasSetter_;
+ }));
// Converts an array returned from Runtime_GetOwnProperty to an actual
@@ -619,7 +623,7 @@ function GetTrap(handler, name, defaultTrap) {
throw MakeTypeError("handler_trap_missing", [handler, name]);
}
trap = defaultTrap;
- } else if (!IS_FUNCTION(trap)) {
+ } else if (!IS_SPEC_FUNCTION(trap)) {
throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
}
return trap;
@@ -973,7 +977,7 @@ function ObjectDefineProperty(obj, p, attributes) {
// Clone the attributes object for protection.
// TODO(rossberg): not spec'ed yet, so not sure if this should involve
// non-own properties as it does (or non-enumerable ones, as it doesn't?).
- var attributesClone = {}
+ var attributesClone = {};
for (var a in attributes) {
attributesClone[a] = attributes[a];
}
@@ -1037,7 +1041,16 @@ function ProxyFix(obj) {
if (IS_UNDEFINED(props)) {
throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
}
- %Fix(obj);
+
+ if (IS_SPEC_FUNCTION(obj)) {
+ var callTrap = %GetCallTrap(obj);
+ var constructTrap = %GetConstructTrap(obj);
+ var code = DelegateCallAndConstruct(callTrap, constructTrap);
+ %Fix(obj); // becomes a regular function
+ %SetCode(obj, code);
+ } else {
+ %Fix(obj);
+ }
ObjectDefineProperties(obj, props);
}
@@ -1168,10 +1181,11 @@ function ObjectIsExtensible(obj) {
%SetExpectedNumberOfProperties($Object, 4);
// ----------------------------------------------------------------------------
+// Object
-
-function SetupObject() {
- // Setup non-enumerable functions on the Object.prototype object.
+function SetUpObject() {
+ %CheckIsBootstrapping();
+ // Set Up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
@@ -1201,8 +1215,7 @@ function SetupObject() {
));
}
-SetupObject();
-
+SetUpObject();
// ----------------------------------------------------------------------------
// Boolean
@@ -1233,14 +1246,16 @@ function BooleanValueOf() {
// ----------------------------------------------------------------------------
-function SetupBoolean() {
+function SetUpBoolean () {
+ %CheckIsBootstrapping();
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
"valueOf", BooleanValueOf
));
}
-SetupBoolean();
+SetUpBoolean();
+
// ----------------------------------------------------------------------------
// Number
@@ -1354,9 +1369,10 @@ function NumberToPrecision(precision) {
// ----------------------------------------------------------------------------
-function SetupNumber() {
+function SetUpNumber() {
+ %CheckIsBootstrapping();
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
- // Setup the constructor property on the Number prototype object.
+ // Set up the constructor property on the Number prototype object.
%SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5);
@@ -1385,7 +1401,7 @@ function SetupNumber() {
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number);
- // Setup non-enumerable functions on the Number prototype object.
+ // Set up non-enumerable functions on the Number prototype object.
InstallFunctions($Number.prototype, DONT_ENUM, $Array(
"toString", NumberToString,
"toLocaleString", NumberToLocaleString,
@@ -1396,7 +1412,7 @@ function SetupNumber() {
));
}
-SetupNumber();
+SetUpNumber();
// ----------------------------------------------------------------------------
@@ -1405,6 +1421,10 @@ SetupNumber();
$Function.prototype.constructor = $Function;
function FunctionSourceString(func) {
+ while (%IsJSFunctionProxy(func)) {
+ func = %GetCallTrap(func);
+ }
+
if (!IS_FUNCTION(func)) {
throw new $TypeError('Function.prototype.toString is not generic');
}
@@ -1434,12 +1454,13 @@ function FunctionToString() {
// ES5 15.3.4.5
function FunctionBind(this_arg) { // Length is 1.
- if (!IS_FUNCTION(this)) {
+ if (!IS_SPEC_FUNCTION(this)) {
throw new $TypeError('Bind must be called on a function');
}
// this_arg is not an argument that should be bound.
var argc_bound = (%_ArgumentsLength() || 1) - 1;
var fn = this;
+
if (argc_bound == 0) {
var result = function() {
if (%_IsConstructCall()) {
@@ -1448,8 +1469,7 @@ function FunctionBind(this_arg) { // Length is 1.
// materializing it and guarantee that this function will be optimized.
return %NewObjectFromBound(fn, null);
}
-
- return fn.apply(this_arg, arguments);
+ return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength());
};
} else {
var bound_args = new InternalArray(argc_bound);
@@ -1479,7 +1499,7 @@ function FunctionBind(this_arg) { // Length is 1.
for (var i = 0; i < argc; i++) {
args[argc_bound + i] = %_Arguments(i);
}
- return fn.apply(this_arg, args);
+ return %Apply(fn, this_arg, args, 0, argc + argc_bound);
};
}
@@ -1490,11 +1510,16 @@ function FunctionBind(this_arg) { // Length is 1.
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
- // Set the correct length.
- var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
%FunctionRemovePrototype(result);
%FunctionSetBound(result);
- %BoundFunctionSetLength(result, length);
+ // Set the correct length. If this is a function proxy, this.length might
+ // throw, or return a bogus result. Leave length alone in that case.
+ // TODO(rossberg): This is underspecified in the current proxy proposal.
+ try {
+ var old_length = ToInteger(this.length);
+ var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0;
+ %BoundFunctionSetLength(result, length);
+ } catch(x) {}
return result;
}
@@ -1525,11 +1550,12 @@ function NewFunction(arg1) { // length == 1
// ----------------------------------------------------------------------------
-function SetupFunction() {
+function SetUpFunction() {
+ %CheckIsBootstrapping();
InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind,
"toString", FunctionToString
));
}
-SetupFunction();
+SetUpFunction();
diff --git a/src/v8threads.h b/src/v8threads.h
index 3ba823a7..4002bb36 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -54,6 +54,7 @@ class ThreadState {
// Get data area for archiving a thread.
char* data() { return data_; }
+
private:
explicit ThreadState(ThreadManager* thread_manager);
diff --git a/src/variables.cc b/src/variables.cc
index e82e6741..971061b0 100644
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -53,34 +53,6 @@ const char* Variable::Mode2String(Mode mode) {
}
-Property* Variable::AsProperty() const {
- return rewrite_ == NULL ? NULL : rewrite_->AsProperty();
-}
-
-
-Slot* Variable::AsSlot() const { return rewrite_; }
-
-
-bool Variable::IsStackAllocated() const {
- return rewrite_ != NULL && rewrite_->IsStackAllocated();
-}
-
-
-bool Variable::IsParameter() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::PARAMETER;
-}
-
-
-bool Variable::IsStackLocal() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::LOCAL;
-}
-
-
-bool Variable::IsContextSlot() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::CONTEXT;
-}
-
-
Variable::Variable(Scope* scope,
Handle<String> name,
Mode mode,
@@ -90,8 +62,9 @@ Variable::Variable(Scope* scope,
name_(name),
mode_(mode),
kind_(kind),
+ location_(UNALLOCATED),
+ index_(-1),
local_if_not_shadowed_(NULL),
- rewrite_(NULL),
is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_scope_(false),
is_used_(false) {
diff --git a/src/variables.h b/src/variables.h
index 2095555a..56c8dabd 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -74,6 +74,33 @@ class Variable: public ZoneObject {
ARGUMENTS
};
+ enum Location {
+ // Before and during variable allocation, a variable whose location is
+ // not yet determined. After allocation, a variable looked up as a
+ // property on the global object (and possibly absent). name() is the
+ // variable name, index() is invalid.
+ UNALLOCATED,
+
+ // A slot in the parameter section on the stack. index() is the
+ // parameter index, counting left-to-right. The reciever is index -1;
+ // the first parameter is index 0.
+ PARAMETER,
+
+ // A slot in the local section on the stack. index() is the variable
+ // index in the stack frame, starting at 0.
+ LOCAL,
+
+ // An indexed slot in a heap context. index() is the variable index in
+ // the context object on the heap, starting at 0. scope() is the
+ // corresponding scope.
+ CONTEXT,
+
+ // A named slot in a heap context. name() is the variable name in the
+ // context object on the heap, with lookup starting at the current
+ // context. index() is invalid.
+ LOOKUP
+ };
+
Variable(Scope* scope,
Handle<String> name,
Mode mode,
@@ -83,10 +110,6 @@ class Variable: public ZoneObject {
// Printing support
static const char* Mode2String(Mode mode);
- // Type testing & conversion. Global variables are not slots.
- Property* AsProperty() const;
- Slot* AsSlot() const;
-
bool IsValidLeftHandSide() { return is_valid_LHS_; }
// The source code for an eval() call may refer to a variable that is
@@ -111,10 +134,12 @@ class Variable: public ZoneObject {
return !is_this() && name().is_identical_to(n);
}
- bool IsStackAllocated() const;
- bool IsParameter() const; // Includes 'this'.
- bool IsStackLocal() const;
- bool IsContextSlot() const;
+ bool IsUnallocated() const { return location_ == UNALLOCATED; }
+ bool IsParameter() const { return location_ == PARAMETER; }
+ bool IsStackLocal() const { return location_ == LOCAL; }
+ bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
+ bool IsContextSlot() const { return location_ == CONTEXT; }
+ bool IsLookupSlot() const { return location_ == LOOKUP; }
bool is_dynamic() const {
return (mode_ == DYNAMIC ||
@@ -141,20 +166,24 @@ class Variable: public ZoneObject {
local_if_not_shadowed_ = local;
}
- Slot* rewrite() const { return rewrite_; }
- void set_rewrite(Slot* slot) { rewrite_ = slot; }
+ Location location() const { return location_; }
+ int index() const { return index_; }
+
+ void AllocateTo(Location location, int index) {
+ location_ = location;
+ index_ = index;
+ }
private:
Scope* scope_;
Handle<String> name_;
Mode mode_;
Kind kind_;
+ Location location_;
+ int index_;
Variable* local_if_not_shadowed_;
- // Code generation.
- Slot* rewrite_;
-
// Valid as a LHS? (const and this are not valid LHS, for example)
bool is_valid_LHS_;
diff --git a/src/version.cc b/src/version.cc
index 1a7c7516..7f916e17 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -33,9 +33,9 @@
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
-#define MINOR_VERSION 5
-#define BUILD_NUMBER 10
-#define PATCH_LEVEL 24
+#define MINOR_VERSION 6
+#define BUILD_NUMBER 6
+#define PATCH_LEVEL 11
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/weakmap.js b/src/weakmap.js
index 3d261e5a..5fb51510 100644
--- a/src/weakmap.js
+++ b/src/weakmap.js
@@ -80,13 +80,11 @@ function WeakMapDelete(key) {
// -------------------------------------------------------------------
-function SetupWeakMap() {
+(function () {
+ %CheckIsBootstrapping();
// Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);
- // Set up the WeakMap prototype object.
- %FunctionSetPrototype($WeakMap, new $WeakMap());
-
// Set up the constructor property on the WeakMap prototype object.
%SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
@@ -97,7 +95,4 @@ function SetupWeakMap() {
"has", WeakMapHas,
"delete", WeakMapDelete
));
-}
-
-
-SetupWeakMap();
+})();
diff --git a/src/win32-math.cc b/src/win32-math.cc
new file mode 100644
index 00000000..3410872b
--- /dev/null
+++ b/src/win32-math.cc
@@ -0,0 +1,106 @@
+// Copyright 2011 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.
+
+// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
+// refer to The Open Group Base Specification for specification of the correct
+// semantics for these functions.
+// (http://www.opengroup.org/onlinepubs/000095399/)
+#ifdef _MSC_VER
+
+#undef V8_WIN32_LEAN_AND_MEAN
+#define V8_WIN32_HEADERS_FULL
+#include "win32-headers.h"
+#include <limits.h> // Required for INT_MAX etc.
+#include <math.h>
+#include <float.h> // Required for DBL_MAX and on Win32 for finite()
+#include "win32-math.h"
+
+#include "checks.h"
+
+namespace v8 {
+
+// Test for finite value - usually defined in math.h
+int isfinite(double x) {
+ return _finite(x);
+}
+
+} // namespace v8
+
+
+// Test for a NaN (not a number) value - usually defined in math.h
+int isnan(double x) {
+ return _isnan(x);
+}
+
+
+// Test for infinity - usually defined in math.h
+int isinf(double x) {
+ return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
+}
+
+
+// Test if x is less than y and both nominal - usually defined in math.h
+int isless(double x, double y) {
+ return isnan(x) || isnan(y) ? 0 : x < y;
+}
+
+
+// Test if x is greater than y and both nominal - usually defined in math.h
+int isgreater(double x, double y) {
+ return isnan(x) || isnan(y) ? 0 : x > y;
+}
+
+
+// Classify floating point number - usually defined in math.h
+int fpclassify(double x) {
+ // Use the MS-specific _fpclass() for classification.
+ int flags = _fpclass(x);
+
+ // Determine class. We cannot use a switch statement because
+ // the _FPCLASS_ constants are defined as flags.
+ if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
+ if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
+ if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
+ if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
+
+ // All cases should be covered by the code above.
+ ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
+ return FP_NAN;
+}
+
+
+// Test sign - usually defined in math.h
+int signbit(double x) {
+ // We need to take care of the special case of both positive
+ // and negative versions of zero.
+ if (x == 0)
+ return _fpclass(x) & _FPCLASS_NZ;
+ else
+ return x < 0;
+}
+
+#endif // _MSC_VER
diff --git a/src/win32-math.h b/src/win32-math.h
new file mode 100644
index 00000000..68759990
--- /dev/null
+++ b/src/win32-math.h
@@ -0,0 +1,61 @@
+// Copyright 2011 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.
+
+// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
+// refer to The Open Group Base Specification for specification of the correct
+// semantics for these functions.
+// (http://www.opengroup.org/onlinepubs/000095399/)
+
+#ifndef V8_WIN32_MATH_H_
+#define V8_WIN32_MATH_H_
+
+#ifndef _MSC_VER
+#error Wrong environment, expected MSVC.
+#endif // _MSC_VER
+
+enum {
+ FP_NAN,
+ FP_INFINITE,
+ FP_ZERO,
+ FP_SUBNORMAL,
+ FP_NORMAL
+};
+
+namespace v8 {
+
+int isfinite(double x);
+
+} // namespace v8
+
+int isnan(double x);
+int isinf(double x);
+int isless(double x, double y);
+int isgreater(double x, double y);
+int fpclassify(double x);
+int signbit(double x);
+
+#endif // V8_WIN32_MATH_H_
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index c23eb168..2e373faa 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -453,6 +453,7 @@ class CpuFeatures : public AllStatic {
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
+
public:
explicit Scope(CpuFeature f) {
uint64_t mask = V8_UINT64_C(1) << f;
@@ -472,10 +473,12 @@ class CpuFeatures : public AllStatic {
isolate_->set_enabled_cpu_features(old_enabled_);
}
}
+
private:
Isolate* isolate_;
uint64_t old_enabled_;
#else
+
public:
explicit Scope(CpuFeature f) {}
#endif
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 7c6f7e32..db06909d 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -655,15 +655,16 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
- Label non_function;
+ Label slow, non_function;
// The function to call is at position n+1 on the stack.
__ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
__ JumpIfSmi(rdi, &non_function);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
- __ j(not_equal, &non_function);
+ __ j(not_equal, &slow);
// 3a. Patch the first argument if necessary when calling a function.
Label shift_arguments;
+ __ Set(rdx, 0); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
@@ -701,6 +702,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ push(rbx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ movq(rbx, rax);
+ __ Set(rdx, 0); // indicate regular JS_FUNCTION
__ pop(rax);
__ SmiToInteger32(rax, rax);
@@ -725,14 +727,19 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ jmp(&shift_arguments);
}
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ Set(rdx, 1); // indicate function proxy
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
+ __ j(equal, &shift_arguments);
+ __ bind(&non_function);
+ __ Set(rdx, 2); // indicate non-function
- // 3b. Patch the first argument when calling a non-function. The
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
- __ bind(&non_function);
__ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
- __ Set(rdi, 0);
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -749,13 +756,26 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ decq(rax); // One fewer argument (first argument is new receiver).
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
- { Label function;
- __ testq(rdi, rdi);
- __ j(not_zero, &function);
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
+ { Label function, non_proxy;
+ __ testq(rdx, rdx);
+ __ j(zero, &function);
__ Set(rbx, 0);
- __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(rcx, CALL_AS_METHOD);
+ __ cmpq(rdx, Immediate(1));
+ __ j(not_equal, &non_proxy);
+
+ __ pop(rdx); // return address
+ __ push(rdi); // re-add proxy object as additional argument
+ __ push(rdx);
+ __ incq(rax);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -797,11 +817,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
static const int kArgumentsOffset = 2 * kPointerSize;
static const int kReceiverOffset = 3 * kPointerSize;
static const int kFunctionOffset = 4 * kPointerSize;
+
__ push(Operand(rbp, kFunctionOffset));
__ push(Operand(rbp, kArgumentsOffset));
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -831,16 +852,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(rax); // limit
__ push(Immediate(0)); // index
- // Change context eagerly to get the right global object if
- // necessary.
+ // Get the receiver.
+ __ movq(rbx, Operand(rbp, kReceiverOffset));
+
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
__ movq(rdi, Operand(rbp, kFunctionOffset));
- __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ j(not_equal, &push_receiver);
- // Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
- __ movq(rbx, Operand(rbp, kReceiverOffset));
+ // Change context eagerly to get the right global object if necessary.
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
// Do not transform the receiver for strict mode functions.
+ Label call_to_object, use_global_receiver;
__ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
@@ -913,14 +938,30 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ j(not_equal, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(rax);
__ SmiToInteger32(rax, rax);
__ movq(rdi, Operand(rbp, kFunctionOffset));
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ j(not_equal, &call_proxy);
__ InvokeFunction(rdi, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ LeaveInternalFrame();
- __ ret(3 * kPointerSize); // remove function, receiver, and arguments
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(rdi); // add function proxy as last argument
+ __ incq(rax);
+ __ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_METHOD);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 9237a0a3..df4438b7 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2712,7 +2712,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, isolate);
+ Isolate::kPendingExceptionAddress, isolate);
Operand pending_exception_operand =
masm->ExternalOperand(pending_exception_address, rbx);
__ movq(rax, pending_exception_operand);
@@ -3232,7 +3232,7 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -3257,7 +3257,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
// Check that the function really is a JavaScript function.
- __ JumpIfSmi(rdi, &slow);
+ __ JumpIfSmi(rdi, &non_function);
// Goto slow case if we do not have a function.
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &slow);
@@ -3284,15 +3284,32 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
+ __ j(not_equal, &non_function);
+ __ pop(rcx);
+ __ push(rdi); // put proxy as additional argument under return address
+ __ push(rcx);
+ __ Set(rax, argc_ + 1);
+ __ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_FUNCTION);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ jmp(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
__ Set(rax, argc_);
__ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_METHOD);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
- __ SetCallKind(rcx, CALL_AS_METHOD);
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
@@ -3428,7 +3445,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// Retrieve the pending exception and clear the variable.
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, masm->isolate());
+ Isolate::kPendingExceptionAddress, masm->isolate());
Operand pending_exception_operand =
masm->ExternalOperand(pending_exception_address);
__ movq(rax, pending_exception_operand);
@@ -3568,14 +3585,14 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
Isolate* isolate = masm->isolate();
// Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate);
+ ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate);
{
Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
__ push(c_entry_fp_operand);
}
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
__ Load(rax, js_entry_sp);
__ testq(rax, rax);
__ j(not_zero, &not_outermost_js);
@@ -3593,7 +3610,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate);
__ Store(pending_exception, rax);
__ movq(rax, Failure::Exception(), RelocInfo::NONE);
@@ -3938,7 +3955,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ testb(result_, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string);
@@ -4195,8 +4213,9 @@ void StringAddStub::Generate(MacroAssembler* masm) {
Label non_ascii, allocated, ascii_data;
__ movl(rcx, r8);
__ and_(rcx, r9);
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ testl(rcx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testl(rcx, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii);
__ bind(&ascii_data);
// Allocate an acsii cons string.
@@ -4225,7 +4244,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
- __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime);
+ __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime);
__ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not
@@ -4254,10 +4273,11 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r8: instance type of first string
// r9: instance type of second string
Label non_ascii_string_add_flat_result;
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ testl(r8, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testl(r8, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii_string_add_flat_result);
- __ testl(r9, Immediate(kAsciiStringTag));
+ __ testl(r9, Immediate(kStringEncodingMask));
__ j(zero, &string_add_runtime);
__ bind(&make_flat_ascii_string);
@@ -4295,7 +4315,9 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r8: instance type of first string
// r9: instance type of first string
__ bind(&non_ascii_string_add_flat_result);
- __ and_(r9, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ and_(r9, Immediate(kStringEncodingMask));
__ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both
// flat.
@@ -4639,9 +4661,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime;
- if (FLAG_string_slices) {
- __ jmp(&runtime);
- }
// Stack frame on entry.
// rsp[0]: return address
// rsp[8]: to
@@ -4707,7 +4726,82 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
__ Set(rcx, 2);
- __ bind(&result_longer_than_two);
+ if (FLAG_string_slices) {
+ Label copy_routine;
+ // If coming from the make_two_character_string path, the string
+ // is too short to be sliced anyways.
+ STATIC_ASSERT(2 < SlicedString::kMinLength);
+ __ jmp(&copy_routine);
+ __ bind(&result_longer_than_two);
+
+ // rax: string
+ // rbx: instance type
+ // rcx: sub string length
+ // rdx: from index (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ __ cmpq(rcx, Immediate(SlicedString::kMinLength));
+ // Short slice. Copy instead of slicing.
+ __ j(less, &copy_routine);
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ testb(rbx, Immediate(kStringRepresentationMask));
+ __ j(zero, &seq_string, Label::kNear);
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ testb(rbx, Immediate(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ j(zero, &runtime);
+
+ __ testb(rbx, Immediate(kSlicedNotConsMask));
+ __ j(not_zero, &sliced_string, Label::kNear);
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset),
+ Heap::kEmptyStringRootIndex);
+ __ j(not_equal, &runtime);
+ __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice, Label::kNear);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset));
+ __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice, Label::kNear);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ movq(rdi, rax);
+
+ __ bind(&allocate_slice);
+ // edi: underlying subject string
+ // ebx: instance type of original subject string
+ // edx: offset
+ // ecx: length
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testb(rbx, Immediate(kStringEncodingMask));
+ __ j(zero, &two_byte_slice, Label::kNear);
+ __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime);
+ __ jmp(&set_slice_header, Label::kNear);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime);
+ __ bind(&set_slice_header);
+ __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx);
+ __ Integer32ToSmi(rcx, rcx);
+ __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx);
+ __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi);
+ __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset),
+ Immediate(String::kEmptyHashField));
+ __ jmp(&return_rax);
+
+ __ bind(&copy_routine);
+ } else {
+ __ bind(&result_longer_than_two);
+ }
// rax: string
// rbx: instance type
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index eca349eb..556523fa 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -51,8 +51,7 @@ static unsigned GetPropertyId(Property* property) {
class JumpPatchSite BASE_EMBEDDED {
public:
- explicit JumpPatchSite(MacroAssembler* masm)
- : masm_(masm) {
+ explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
#ifdef DEBUG
info_emitted_ = false;
#endif
@@ -187,14 +186,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -232,7 +231,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
: ArgumentsAccessStub::NEW_NON_STRICT_SLOW);
__ CallStub(&stub);
- Move(arguments->AsSlot(), rax, rbx, rdx);
+ SetVar(arguments, rax, rbx, rdx);
}
if (FLAG_trace) {
@@ -244,18 +243,21 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
if (scope()->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ Declarations");
scope()->VisitIllegalRedeclaration(this);
+
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &ok, Label::kNear);
@@ -355,24 +357,26 @@ void FullCodeGenerator::EmitReturnSequence() {
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ movq(result_register(), slot_operand);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ push(slot_operand);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ MemOperand operand = codegen()->VarOperand(var, result_register());
+ __ push(operand);
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -591,43 +595,53 @@ void FullCodeGenerator::Split(Condition cc,
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return Operand(rbp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return Operand(rax, 0);
+ return Operand(rbp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
- MemOperand location = EmitSlotSearch(source, destination);
- __ movq(destination, location);
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ MemOperand location = VarOperand(var, dest);
+ __ movq(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ movq(location, src);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
- __ RecordWrite(scratch1, offset, src, scratch2);
+ if (var->IsContextSlot()) {
+ int offset = Context::SlotOffset(var->index());
+ __ RecordWrite(scratch0, offset, src, scratch1);
}
}
@@ -658,29 +672,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ movq(Operand(rbp, SlotOffset(slot)), result_register());
+ __ movq(StackOperand(variable), result_register());
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
- __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
+ __ movq(StackOperand(variable), kScratchRegister);
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -693,22 +711,27 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ Check(not_equal, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ movq(ContextOperand(rsi, slot->index()), result_register());
- int offset = Context::SlotOffset(slot->index());
+ __ movq(ContextOperand(rsi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
__ movq(rbx, rsi);
__ RecordWrite(rbx, offset, result_register(), rcx);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
- __ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
+ __ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
// No write barrier since the hole value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ push(rsi);
__ Push(variable->name());
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -723,7 +746,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else {
- __ Push(Smi::FromInt(0)); // no initial value!
+ __ Push(Smi::FromInt(0)); // Indicates no initial value.
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
@@ -732,18 +755,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(rsi); // The context is the first argument.
__ Push(pairs);
- __ Push(Smi::FromInt(is_eval() ? 1 : 0));
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ Push(Smi::FromInt(DeclareGlobalsFlags()));
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1048,10 +1068,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register context = rsi;
Register temp = rdx;
@@ -1101,7 +1120,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global
// load IC call.
__ movq(rax, GlobalObjectOperand());
- __ Move(rcx, slot->var()->name());
+ __ Move(rcx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1110,14 +1129,13 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = rsi;
Register temp = rbx;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1137,60 +1155,31 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to
// return an rsi-based operand (the write barrier cannot be allowed to
// destroy the rsi register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ movq(rax,
- ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, done);
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ movq(rdx,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ Move(rax, key_literal->handle());
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, done);
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
}
+ __ jmp(done);
}
}
@@ -1200,66 +1189,58 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in rcx and the global
- // object on the stack.
- __ Move(rcx, var->name());
- __ movq(rax, GlobalObjectOperand());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(rax);
-
- } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ push(rsi); // Context.
- __ Push(var->name());
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in rcx and the global
+ // object on the stack.
+ __ Move(rcx, var->name());
+ __ movq(rax, GlobalObjectOperand());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(rax);
+ break;
+ }
- context()->Plug(rax);
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ Label done;
+ GetVar(rax, var);
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &done, Label::kNear);
+ if (var->mode() == Variable::LET) {
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ } else { // Variable::CONST
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+ }
+ __ bind(&done);
+ context()->Plug(rax);
+ }
+ break;
+ }
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, rax);
- __ movq(rax, slot_operand);
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &done, Label::kNear);
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- __ bind(&done);
- context()->Plug(rax);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, rax);
- __ movq(rax, slot_operand);
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &done, Label::kNear);
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup slot");
+ __ push(rsi); // Context.
__ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(rax);
- } else {
- context()->Plug(slot);
+ break;
}
}
}
@@ -1279,7 +1260,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rbx, FieldOperand(rcx, literal_offset));
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
- __ j(not_equal, &materialized);
+ __ j(not_equal, &materialized, Label::kNear);
// Create regexp literal using runtime function
// Result will be in rax.
@@ -1744,133 +1725,88 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in rax, variable name in
- // rcx, and the global object on the stack.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ Move(rcx, var->name());
__ movq(rdx, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize();
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
-
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- __ movq(rdx, Operand(rbp, SlotOffset(slot)));
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &skip);
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(rax);
- __ push(rsi);
- __ Push(var->name());
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ movq(rdx, StackOperand(var));
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &skip);
+ __ movq(StackOperand(var), rax);
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(rax);
+ __ push(rsi);
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ movq(rdx, Operand(rbp, SlotOffset(slot)));
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &assign);
- __ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
- }
-
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, rcx);
- // Check for an initialized let binding.
- __ movq(rdx, target);
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &assign, Label::kNear);
- __ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ movq(target, rax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(rax); // Value.
+ __ push(rsi); // Context.
+ __ Push(var->name());
+ __ Push(Smi::FromInt(strict_mode_flag()));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, rcx);
+ __ movq(rdx, location);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &assign, Label::kNear);
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ __ movq(location, rax);
+ if (var->IsContextSlot()) {
__ movq(rdx, rax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(rcx, offset, rdx, rbx);
- break;
+ __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(rax); // Value.
- __ push(rsi); // Context.
- __ Push(var->name());
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
- } else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, rcx);
- // Perform the assignment and issue the write barrier.
- __ movq(target, rax);
- // The value of the assignment is in rax. RecordWrite clobbers its
- // register arguments.
+ } else if (var->mode() != Variable::CONST) {
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, rcx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ movq(rdx, location);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ Check(equal, "Let binding re-initialization.");
+ }
+ // Perform the assignment.
+ __ movq(location, rax);
+ if (var->IsContextSlot()) {
__ movq(rdx, rax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(rcx, offset, rdx, rbx);
- break;
+ __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(rax); // Value.
- __ push(rsi); // Context.
- __ Push(var->name());
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(rax); // Value.
+ __ push(rsi); // Context.
+ __ Push(var->name());
+ __ Push(Smi::FromInt(strict_mode_flag()));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -1990,9 +1926,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2023,9 +1958,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2046,8 +1980,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2069,8 +2002,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
- // Push the strict mode flag.
- __ Push(Smi::FromInt(strict_mode_flag()));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ Push(Smi::FromInt(strict_mode));
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
? Runtime::kResolvePossiblyDirectEvalNoLookup
@@ -2086,18 +2024,18 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
- // resolve the function we need to call and the receiver of the
- // call. Then we call the resolved function using the given
- // arguments.
+ // resolve the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
// Push the arguments.
@@ -2106,15 +2044,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// If we know that eval can only be shadowed by eval-introduced
- // variables we attempt to load the global eval function directly
- // in generated code. If we succeed, there is no need to perform a
+ // variables we attempt to load the global eval function directly in
+ // generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(rax);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2122,13 +2059,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
- // resolve eval.
+ // Push a copy of the function (found below the arguments) and resolve
+ // eval.
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in rax (function) and
// rdx (receiver). Touch up the stack with the right values.
@@ -2137,80 +2072,68 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, rax);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
- // Call to a global variable.
- // Push global object as receiver for the call IC lookup.
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ // Call to a global variable. Push global object as receiver for the
+ // call IC lookup.
__ push(GlobalObjectOperand());
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
-
- __ bind(&slow);
+ // Generate code for loading from variables potentially shadowed by
+ // eval-introduced variables.
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
- // Call the runtime to find the function to call (returned in rax)
- // and the object holding it (returned in rdx).
+ __ bind(&slow);
+ // Call the runtime to find the function to call (returned in rax) and
+ // the object holding it (returned in rdx).
__ push(context_register());
- __ Push(var->name());
+ __ Push(proxy->name());
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(rax); // Function.
__ push(rdx); // Receiver.
- // If fast case code has been generated, emit code to push the
- // function and receiver and have the slow path jump around this
- // code.
+ // If fast case code has been generated, emit code to push the function
+ // and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(rax);
- // The receiver is implicitly the global receiver. Indicate this
- // by passing the hole to the call function stub.
+ // The receiver is implicitly the global receiver. Indicate this by
+ // passing the hole to the call function stub.
__ PushRoot(Heap::kTheHoleValueRootIndex);
__ bind(&call);
}
- // The receiver is either the global receiver or an object found
- // by LoadContextSlot. That object could be the hole if the
- // receiver is implicitly the global object.
+ // The receiver is either the global receiver or an object found by
+ // LoadContextSlot. That object could be the hole if the receiver is
+ // implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ movq(rbx, GlobalObjectOperand());
@@ -3550,10 +3473,9 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Call the JS runtime function using a call IC.
__ Move(rcx, expr->name());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3568,30 +3490,31 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ Push(Smi::FromInt(strict_mode_flag()));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ Push(var->name());
__ Push(Smi::FromInt(kNonStrictMode));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- context()->Plug(false);
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is
+ // not really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3877,7 +3800,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ Move(rcx, proxy->name());
__ movq(rax, GlobalObjectOperand());
@@ -3887,15 +3810,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(rax);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ push(rsi);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 990c171b..9d55594d 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -145,7 +145,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ Test(Operand(elements, r1, times_pointer_size,
kDetailsOffset - kHeapObjectTag),
- Smi::FromInt(PropertyDetails::TypeField::mask()));
+ Smi::FromInt(PropertyDetails::TypeField::kMask));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
@@ -201,9 +201,9 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ Test(Operand(elements,
scratch1,
times_pointer_size,
@@ -720,7 +720,6 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1267,9 +1266,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
rdx);
@@ -1372,10 +1369,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
no_reg);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c182413c..9064a266 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -100,7 +100,8 @@ void LCodeGen::FinishCode(Handle<Code> code) {
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -207,14 +208,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -2219,11 +2220,11 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Immediate(Map::kElementsKindMask));
__ shr(temp, Immediate(Map::kElementsKindShift));
- __ cmpl(temp, Immediate(JSObject::FAST_ELEMENTS));
+ __ cmpl(temp, Immediate(FAST_ELEMENTS));
__ j(equal, &ok, Label::kNear);
- __ cmpl(temp, Immediate(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmpl(temp, Immediate(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less, &fail, Label::kNear);
- __ cmpl(temp, Immediate(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmpl(temp, Immediate(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed");
@@ -2267,7 +2268,7 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ movq(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
- JSObject::FAST_ELEMENTS,
+ FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
@@ -2288,14 +2289,14 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
- JSObject::FAST_DOUBLE_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
offset);
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(result, double_load_operand);
}
@@ -2304,7 +2305,7 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
@@ -2325,35 +2326,35 @@ Operand LCodeGen::BuildFastArrayOperand(
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsxbq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ movzxbq(result, operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsxwq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzxwq(result, operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ movsxlq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(result, operand);
__ testl(result, result);
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2361,12 +2362,12 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(negative, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -2952,8 +2953,8 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
- arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
}
@@ -2965,7 +2966,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ Move(rcx, instr->name());
CallCode(ic, mode, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -2976,7 +2977,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ Drop(1);
@@ -2988,7 +2989,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ Move(rcx, instr->name());
CallCode(ic, mode, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3061,37 +3062,37 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
__ movss(operand, value);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(operand, ToDoubleRegister(instr->value()));
} else {
Register value(ToRegister(instr->value()));
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movb(operand, value);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movw(operand, value);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(operand, value);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3164,7 +3165,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(double_store_operand, value);
}
@@ -3251,7 +3252,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ testb(result, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 0622e9d2..8cb4cece 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -218,7 +218,7 @@ class LCodeGen BASE_EMBEDDED {
Operand BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 9dc925d5..5fc56462 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -313,13 +313,13 @@ void LCallKeyed::PrintDataTo(StringStream* stream) {
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -539,7 +539,8 @@ LChunk* LChunkBuilder::Build() {
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -705,9 +706,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -990,13 +989,10 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1006,6 +1002,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1014,7 +1011,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1844,15 +1841,15 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1861,7 +1858,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
AssignEnvironment(load_instr) : load_instr;
}
@@ -1911,21 +1908,21 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS;
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 05b66376..d169bf6d 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1155,7 +1155,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1631,7 +1631,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2146,8 +2146,7 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index b51d531e..9cfc9b65 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2415,7 +2415,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
}
// Save the current handler.
Operand handler_operand =
- ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate()));
push(handler_operand);
// Link this handler.
movq(handler_operand, rsp);
@@ -2426,7 +2426,7 @@ void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
// Unlink this handler.
Operand handler_operand =
- ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate()));
pop(handler_operand);
// Remove the remaining fields.
addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
@@ -2446,7 +2446,7 @@ void MacroAssembler::Throw(Register value) {
movq(rax, value);
}
- ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Operand handler_operand = ExternalOperand(handler_address);
movq(rsp, handler_operand);
// get next in chain
@@ -2482,7 +2482,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
movq(rax, value);
}
// Fetch top stack handler.
- ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Load(rsp, handler_address);
// Unwind the handlers until the ENTRY handler is found.
@@ -2505,12 +2505,12 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
Set(rax, static_cast<int64_t>(false));
Store(external_caught, rax);
// Set pending exception and rax to out of memory exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate());
movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
Store(pending_exception, rax);
@@ -2567,7 +2567,7 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Immediate(Map::kMaximumBitField2FastElementValue));
j(above, fail, distance);
@@ -3041,8 +3041,8 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
movq(r14, rax); // Backup rax in callee-save register.
}
- Store(ExternalReference(Isolate::k_c_entry_fp_address, isolate()), rbp);
- Store(ExternalReference(Isolate::k_context_address, isolate()), rsi);
+ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
+ Store(ExternalReference(Isolate::kContextAddress, isolate()), rsi);
}
@@ -3132,7 +3132,7 @@ void MacroAssembler::LeaveApiExitFrame() {
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Isolate::k_context_address, isolate());
+ ExternalReference context_address(Isolate::kContextAddress, isolate());
Operand context_operand = ExternalOperand(context_address);
movq(rsi, context_operand);
#ifdef DEBUG
@@ -3140,7 +3140,7 @@ void MacroAssembler::LeaveExitFrameEpilogue() {
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
Operand c_entry_fp_operand = ExternalOperand(c_entry_fp_address);
movq(c_entry_fp_operand, Immediate(0));
@@ -3303,7 +3303,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
- Smi::FromInt(PropertyDetails::TypeField::mask()));
+ Smi::FromInt(PropertyDetails::TypeField::kMask));
j(not_zero, miss);
// Get the value at the masked, scaled index.
@@ -3623,7 +3623,7 @@ void MacroAssembler::AllocateAsciiString(Register result,
}
-void MacroAssembler::AllocateConsString(Register result,
+void MacroAssembler::AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
@@ -3659,6 +3659,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map. The other fields are left uninitialized.
+ LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex);
+ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map. The other fields are left uninitialized.
+ LoadRoot(kScratchRegister, Heap::kSlicedAsciiStringMapRootIndex);
+ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
+}
+
+
// Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed.
// Destination is incremented by length, source, length and scratch are
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 47ce01bd..e7eb104c 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -921,7 +921,7 @@ class MacroAssembler: public Assembler {
// Allocate a raw cons string object. Only the map field of the result is
// initialized.
- void AllocateConsString(Register result,
+ void AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
@@ -930,6 +930,17 @@ class MacroAssembler: public Assembler {
Register scratch2,
Label* gc_required);
+ // Allocate a raw sliced string object. Only the map field of the result is
+ // initialized.
+ void AllocateTwoByteSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+
// ---------------------------------------------------------------------------
// Support functions.
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 5ea72579..76d25557 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -2537,7 +2537,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
// -- rsp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -2996,7 +2996,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
// -- rsp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(rdx,
@@ -3227,7 +3227,7 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3255,29 +3255,29 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(rcx, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
break;
default:
@@ -3293,7 +3293,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// xmm0: value as double.
ASSERT(kSmiValueSize == 32);
- if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// For the UnsignedInt array type, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3317,8 +3317,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
__ movq(rax, rcx);
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(rcx, rbx, &slow);
@@ -3361,7 +3361,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -3391,7 +3391,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rbx: elements array
// rdi: untagged key
Label check_heap_number;
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Float to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(rax, &slow);
} else {
@@ -3402,7 +3402,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255].
Label done;
__ testl(rdx, Immediate(0xFFFFFF00));
@@ -3413,39 +3413,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
}
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2ss(xmm0, rdx);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2sd(xmm0, rdx);
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
__ ret(0);
// TODO(danno): handle heap number -> pixel array conversion
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
__ bind(&check_heap_number);
// rax: value
// rcx: key (a smi)
@@ -3464,11 +3464,11 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rdi: untagged index
// rbx: base pointer of external storage
// top of FPU stack: value
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, xmm0);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
__ ret(0);
} else {
@@ -3482,30 +3482,30 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rdi: untagged index
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
// Convert to int64, so that NaN and infinities become
// 0x8000000000000000, which is zero mod 2^32.
__ cvttsd2siq(rdx, xmm0);
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/zone-inl.h b/src/zone-inl.h
index 6e2d558a..4870105f 100644
--- a/src/zone-inl.h
+++ b/src/zone-inl.h
@@ -55,7 +55,12 @@ inline void* Zone::New(int size) {
// Check if the requested size is available without expanding.
Address result = position_;
- if ((position_ += size) > limit_) result = NewExpand(size);
+
+ if (size > limit_ - position_) {
+ result = NewExpand(size);
+ } else {
+ position_ += size;
+ }
// Check that the result has the proper alignment and return it.
ASSERT(IsAddressAligned(result, kAlignment, 0));
diff --git a/src/zone.cc b/src/zone.cc
index 7574778f..2d14d137 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -168,7 +168,7 @@ Address Zone::NewExpand(int size) {
// Make sure the requested size is already properly aligned and that
// there isn't enough room in the Zone to satisfy the request.
ASSERT(size == RoundDown(size, kAlignment));
- ASSERT(position_ + size > limit_);
+ ASSERT(size > limit_ - position_);
// Compute the new segment size. We use a 'high water mark'
// strategy, where we increase the segment size every time we expand
@@ -177,7 +177,13 @@ Address Zone::NewExpand(int size) {
Segment* head = segment_head_;
int old_size = (head == NULL) ? 0 : head->size();
static const int kSegmentOverhead = sizeof(Segment) + kAlignment;
- int new_size = kSegmentOverhead + size + (old_size << 1);
+ int new_size_no_overhead = size + (old_size << 1);
+ int new_size = kSegmentOverhead + new_size_no_overhead;
+ // Guard against integer overflow.
+ if (new_size_no_overhead < size || new_size < kSegmentOverhead) {
+ V8::FatalProcessOutOfMemory("Zone");
+ return NULL;
+ }
if (new_size < kMinimumSegmentSize) {
new_size = kMinimumSegmentSize;
} else if (new_size > kMaximumSegmentSize) {
@@ -196,6 +202,11 @@ Address Zone::NewExpand(int size) {
// Recompute 'top' and 'limit' based on the new segment.
Address result = RoundUp(segment->start(), kAlignment);
position_ = result + size;
+ // Check for address overflow.
+ if (position_ < result) {
+ V8::FatalProcessOutOfMemory("Zone");
+ return NULL;
+ }
limit_ = segment->end();
ASSERT(position_ <= limit_);
return result;